]> git.karo-electronics.de Git - linux-beck.git/commitdiff
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 2 Mar 2010 15:55:08 +0000 (07:55 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 2 Mar 2010 15:55:08 +0000 (07:55 -0800)
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1341 commits)
  virtio_net: remove forgotten assignment
  be2net: fix tx completion polling
  sis190: fix cable detect via link status poll
  net: fix protocol sk_buff field
  bridge: Fix build error when IGMP_SNOOPING is not enabled
  bnx2x: Tx barriers and locks
  scm: Only support SCM_RIGHTS on unix domain sockets.
  vhost-net: restart tx poll on sk_sndbuf full
  vhost: fix get_user_pages_fast error handling
  vhost: initialize log eventfd context pointer
  vhost: logging thinko fix
  wireless: convert to use netdev_for_each_mc_addr
  ethtool: do not set some flags, if others failed
  ipoib: returned back addrlen check for mc addresses
  netlink: Adding inode field to /proc/net/netlink
  axnet_cs: add new id
  bridge: Make IGMP snooping depend upon BRIDGE.
  bridge: Add multicast count/interval sysfs entries
  bridge: Add hash elasticity/max sysfs entries
  bridge: Add multicast_snooping sysfs toggle
  ...

Trivial conflicts in Documentation/feature-removal-schedule.txt

1034 files changed:
Documentation/ABI/testing/sysfs-block
Documentation/arm/memory.txt
Documentation/block/queue-sysfs.txt
Documentation/cachetlb.txt
Documentation/feature-removal-schedule.txt
Documentation/input/sentelic.txt
Documentation/sound/alsa/ALSA-Configuration.txt
Documentation/sound/alsa/HD-Audio-Models.txt
Documentation/sound/alsa/HD-Audio.txt
arch/alpha/include/asm/pgtable.h
arch/arm/Kconfig
arch/arm/Makefile
arch/arm/boot/compressed/Makefile
arch/arm/boot/compressed/decompress.c [new file with mode: 0644]
arch/arm/boot/compressed/head.S
arch/arm/boot/compressed/misc.c
arch/arm/boot/compressed/vmlinux.lds.in
arch/arm/common/clkdev.c
arch/arm/common/dmabounce.c
arch/arm/common/vic.c
arch/arm/configs/at572d940hfek_defconfig [new file with mode: 0644]
arch/arm/configs/omap_4430sdp_defconfig
arch/arm/include/asm/atomic.h
arch/arm/include/asm/cacheflush.h
arch/arm/include/asm/clkdev.h
arch/arm/include/asm/dma-mapping.h
arch/arm/include/asm/io.h
arch/arm/include/asm/mach/time.h
arch/arm/include/asm/memory.h
arch/arm/include/asm/mmu.h
arch/arm/include/asm/mmu_context.h
arch/arm/include/asm/page.h
arch/arm/include/asm/perf_event.h [new file with mode: 0644]
arch/arm/include/asm/pgtable-nommu.h
arch/arm/include/asm/pmu.h [new file with mode: 0644]
arch/arm/include/asm/setup.h
arch/arm/include/asm/smp_plat.h
arch/arm/include/asm/spinlock.h
arch/arm/include/asm/system.h
arch/arm/include/asm/thread_info.h
arch/arm/include/asm/tlbflush.h
arch/arm/kernel/Makefile
arch/arm/kernel/asm-offsets.c
arch/arm/kernel/debug.S
arch/arm/kernel/leds.c [new file with mode: 0644]
arch/arm/kernel/perf_event.c [new file with mode: 0644]
arch/arm/kernel/pmu.c [new file with mode: 0644]
arch/arm/kernel/ptrace.c
arch/arm/kernel/setup.c
arch/arm/kernel/time.c
arch/arm/kernel/traps.c
arch/arm/kernel/vmlinux.lds.S
arch/arm/mach-aaec2000/include/mach/debug-macro.S
arch/arm/mach-at91/Kconfig
arch/arm/mach-at91/Makefile
arch/arm/mach-at91/at572d940hf.c [new file with mode: 0644]
arch/arm/mach-at91/at572d940hf_devices.c [new file with mode: 0644]
arch/arm/mach-at91/board-at572d940hf_ek.c [new file with mode: 0644]
arch/arm/mach-at91/clock.c
arch/arm/mach-at91/clock.h
arch/arm/mach-at91/generic.h
arch/arm/mach-at91/include/mach/at572d940hf.h [new file with mode: 0644]
arch/arm/mach-at91/include/mach/at572d940hf_matrix.h [new file with mode: 0644]
arch/arm/mach-at91/include/mach/at91_pmc.h
arch/arm/mach-at91/include/mach/board.h
arch/arm/mach-at91/include/mach/cpu.h
arch/arm/mach-at91/include/mach/debug-macro.S
arch/arm/mach-at91/include/mach/hardware.h
arch/arm/mach-at91/include/mach/timex.h
arch/arm/mach-bcmring/core.c
arch/arm/mach-clps711x/include/mach/debug-macro.S
arch/arm/mach-davinci/Kconfig
arch/arm/mach-davinci/Makefile
arch/arm/mach-davinci/board-da830-evm.c
arch/arm/mach-davinci/board-da850-evm.c
arch/arm/mach-davinci/board-dm355-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/cdce949.c [new file with mode: 0644]
arch/arm/mach-davinci/clock.c
arch/arm/mach-davinci/clock.h
arch/arm/mach-davinci/common.c
arch/arm/mach-davinci/cpuidle.c
arch/arm/mach-davinci/da830.c
arch/arm/mach-davinci/da850.c
arch/arm/mach-davinci/devices-da8xx.c
arch/arm/mach-davinci/dm355.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/cdce949.h [new file with mode: 0644]
arch/arm/mach-davinci/include/mach/common.h
arch/arm/mach-davinci/include/mach/cpuidle.h
arch/arm/mach-davinci/include/mach/da8xx.h
arch/arm/mach-davinci/include/mach/debug-macro.S
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/edma.h
arch/arm/mach-davinci/include/mach/hardware.h
arch/arm/mach-davinci/include/mach/i2c.h
arch/arm/mach-davinci/include/mach/memory.h
arch/arm/mach-davinci/include/mach/mux.h
arch/arm/mach-davinci/include/mach/pm.h [new file with mode: 0644]
arch/arm/mach-davinci/include/mach/psc.h
arch/arm/mach-davinci/include/mach/spi.h [new file with mode: 0644]
arch/arm/mach-davinci/include/mach/timex.h
arch/arm/mach-davinci/io.c
arch/arm/mach-davinci/pm.c [new file with mode: 0644]
arch/arm/mach-davinci/psc.c
arch/arm/mach-davinci/sleep.S [new file with mode: 0644]
arch/arm/mach-dove/include/mach/debug-macro.S
arch/arm/mach-dove/include/mach/vmalloc.h
arch/arm/mach-ebsa110/include/mach/debug-macro.S
arch/arm/mach-ep93xx/Kconfig
arch/arm/mach-ep93xx/Makefile
arch/arm/mach-ep93xx/clock.c
arch/arm/mach-ep93xx/core.c
arch/arm/mach-ep93xx/dma-m2p.c
arch/arm/mach-ep93xx/edb93xx.c
arch/arm/mach-ep93xx/gpio.c
arch/arm/mach-ep93xx/include/mach/debug-macro.S
arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h
arch/arm/mach-ep93xx/include/mach/vmalloc.h
arch/arm/mach-ep93xx/simone.c [new file with mode: 0644]
arch/arm/mach-ep93xx/snappercl15.c [new file with mode: 0644]
arch/arm/mach-footbridge/common.c
arch/arm/mach-footbridge/include/mach/debug-macro.S
arch/arm/mach-gemini/include/mach/debug-macro.S
arch/arm/mach-gemini/include/mach/vmalloc.h
arch/arm/mach-h720x/include/mach/debug-macro.S
arch/arm/mach-integrator/core.c
arch/arm/mach-integrator/include/mach/debug-macro.S
arch/arm/mach-integrator/integrator_cp.c
arch/arm/mach-iop13xx/include/mach/debug-macro.S
arch/arm/mach-iop13xx/io.c
arch/arm/mach-iop32x/include/mach/debug-macro.S
arch/arm/mach-iop32x/include/mach/vmalloc.h
arch/arm/mach-iop33x/include/mach/debug-macro.S
arch/arm/mach-iop33x/include/mach/vmalloc.h
arch/arm/mach-ixp2000/include/mach/debug-macro.S
arch/arm/mach-ixp2000/include/mach/vmalloc.h
arch/arm/mach-ixp23xx/include/mach/debug-macro.S
arch/arm/mach-ixp23xx/include/mach/vmalloc.h
arch/arm/mach-ixp4xx/common.c
arch/arm/mach-ixp4xx/include/mach/debug-macro.S
arch/arm/mach-ixp4xx/include/mach/vmalloc.h
arch/arm/mach-kirkwood/include/mach/debug-macro.S
arch/arm/mach-kirkwood/include/mach/vmalloc.h
arch/arm/mach-ks8695/include/mach/debug-macro.S
arch/arm/mach-l7200/include/mach/debug-macro.S
arch/arm/mach-lh7a40x/include/mach/debug-macro.S
arch/arm/mach-lh7a40x/include/mach/vmalloc.h
arch/arm/mach-loki/include/mach/debug-macro.S
arch/arm/mach-loki/include/mach/vmalloc.h
arch/arm/mach-mmp/clock.c
arch/arm/mach-mmp/clock.h
arch/arm/mach-mmp/include/mach/debug-macro.S
arch/arm/mach-mmp/include/mach/vmalloc.h
arch/arm/mach-mmp/pxa168.c
arch/arm/mach-mmp/pxa910.c
arch/arm/mach-msm/include/mach/debug-macro.S
arch/arm/mach-msm/io.c
arch/arm/mach-mv78xx0/include/mach/debug-macro.S
arch/arm/mach-mv78xx0/include/mach/vmalloc.h
arch/arm/mach-mx1/clock.c
arch/arm/mach-mx2/clock_imx21.c
arch/arm/mach-mx2/clock_imx27.c
arch/arm/mach-mx25/clock.c
arch/arm/mach-mx3/clock-imx35.c
arch/arm/mach-mx3/clock.c
arch/arm/mach-mxc91231/clock.c
arch/arm/mach-netx/include/mach/debug-macro.S
arch/arm/mach-nomadik/include/mach/debug-macro.S
arch/arm/mach-nomadik/include/mach/vmalloc.h
arch/arm/mach-ns9xxx/include/mach/debug-macro.S
arch/arm/mach-ns9xxx/include/mach/vmalloc.h
arch/arm/mach-nuc93x/Kconfig [new file with mode: 0644]
arch/arm/mach-nuc93x/Makefile [new file with mode: 0644]
arch/arm/mach-nuc93x/Makefile.boot [new file with mode: 0644]
arch/arm/mach-nuc93x/clock.c [new file with mode: 0644]
arch/arm/mach-nuc93x/clock.h [new file with mode: 0644]
arch/arm/mach-nuc93x/cpu.c [new file with mode: 0644]
arch/arm/mach-nuc93x/cpu.h [new file with mode: 0644]
arch/arm/mach-nuc93x/dev.c [new file with mode: 0644]
arch/arm/mach-nuc93x/include/mach/clkdev.h [new file with mode: 0644]
arch/arm/mach-nuc93x/include/mach/entry-macro.S [new file with mode: 0644]
arch/arm/mach-nuc93x/include/mach/hardware.h [new file with mode: 0644]
arch/arm/mach-nuc93x/include/mach/io.h [new file with mode: 0644]
arch/arm/mach-nuc93x/include/mach/irqs.h [new file with mode: 0644]
arch/arm/mach-nuc93x/include/mach/map.h [new file with mode: 0644]
arch/arm/mach-nuc93x/include/mach/memory.h [new file with mode: 0644]
arch/arm/mach-nuc93x/include/mach/regs-clock.h [new file with mode: 0644]
arch/arm/mach-nuc93x/include/mach/regs-ebi.h [new file with mode: 0644]
arch/arm/mach-nuc93x/include/mach/regs-irq.h [new file with mode: 0644]
arch/arm/mach-nuc93x/include/mach/regs-serial.h [new file with mode: 0644]
arch/arm/mach-nuc93x/include/mach/regs-timer.h [new file with mode: 0644]
arch/arm/mach-nuc93x/include/mach/system.h [new file with mode: 0644]
arch/arm/mach-nuc93x/include/mach/timex.h [new file with mode: 0644]
arch/arm/mach-nuc93x/include/mach/uncompress.h [new file with mode: 0644]
arch/arm/mach-nuc93x/include/mach/vmalloc.h [new file with mode: 0644]
arch/arm/mach-nuc93x/irq.c [new file with mode: 0644]
arch/arm/mach-nuc93x/mach-nuc932evb.c [new file with mode: 0644]
arch/arm/mach-nuc93x/nuc932.c [new file with mode: 0644]
arch/arm/mach-nuc93x/nuc932.h [new file with mode: 0644]
arch/arm/mach-nuc93x/time.c [new file with mode: 0644]
arch/arm/mach-omap1/include/mach/debug-macro.S
arch/arm/mach-omap2/board-4430sdp.c
arch/arm/mach-omap2/include/mach/debug-macro.S
arch/arm/mach-orion5x/include/mach/debug-macro.S
arch/arm/mach-orion5x/include/mach/vmalloc.h
arch/arm/mach-pnx4008/clock.c
arch/arm/mach-pnx4008/clock.h
arch/arm/mach-pnx4008/i2c.c
arch/arm/mach-pnx4008/include/mach/clkdev.h [new file with mode: 0644]
arch/arm/mach-pnx4008/include/mach/debug-macro.S
arch/arm/mach-pnx4008/include/mach/timex.h
arch/arm/mach-pnx4008/pm.c
arch/arm/mach-pnx4008/time.c
arch/arm/mach-pnx4008/time.h [new file with mode: 0644]
arch/arm/mach-pxa/clock.c
arch/arm/mach-pxa/clock.h
arch/arm/mach-pxa/eseries.c
arch/arm/mach-pxa/include/mach/debug-macro.S
arch/arm/mach-pxa/include/mach/vmalloc.h
arch/arm/mach-pxa/pxa25x.c
arch/arm/mach-pxa/pxa27x.c
arch/arm/mach-pxa/pxa300.c
arch/arm/mach-pxa/pxa320.c
arch/arm/mach-pxa/pxa3xx.c
arch/arm/mach-realview/core.c
arch/arm/mach-realview/include/mach/debug-macro.S
arch/arm/mach-realview/include/mach/vmalloc.h
arch/arm/mach-rpc/include/mach/debug-macro.S
arch/arm/mach-s3c2410/include/mach/debug-macro.S
arch/arm/mach-s3c24a0/include/mach/debug-macro.S
arch/arm/mach-s3c24a0/include/mach/vmalloc.h
arch/arm/mach-s3c6400/include/mach/debug-macro.S
arch/arm/mach-s5pc100/include/mach/debug-macro.S
arch/arm/mach-sa1100/include/mach/debug-macro.S
arch/arm/mach-sa1100/include/mach/vmalloc.h
arch/arm/mach-shark/include/mach/debug-macro.S
arch/arm/mach-u300/clock.c
arch/arm/mach-u300/core.c
arch/arm/mach-u300/gpio.c
arch/arm/mach-u300/include/mach/debug-macro.S
arch/arm/mach-u300/include/mach/dma_channels.h [new file with mode: 0644]
arch/arm/mach-u300/include/mach/vmalloc.h
arch/arm/mach-ux500/board-mop500.c
arch/arm/mach-ux500/clock.c
arch/arm/mach-ux500/cpu-u8500.c
arch/arm/mach-ux500/include/mach/debug-macro.S
arch/arm/mach-ux500/include/mach/vmalloc.h
arch/arm/mach-versatile/core.c
arch/arm/mach-versatile/include/mach/debug-macro.S
arch/arm/mach-w90x900/clock.c
arch/arm/mach-w90x900/clock.h
arch/arm/mach-w90x900/cpu.c
arch/arm/mach-w90x900/include/mach/vmalloc.h
arch/arm/mm/Kconfig
arch/arm/mm/alignment.c
arch/arm/mm/cache-fa.S
arch/arm/mm/cache-l2x0.c
arch/arm/mm/cache-v3.S
arch/arm/mm/cache-v4.S
arch/arm/mm/cache-v4wb.S
arch/arm/mm/cache-v4wt.S
arch/arm/mm/cache-v6.S
arch/arm/mm/cache-v7.S
arch/arm/mm/context.c
arch/arm/mm/copypage-feroceon.c
arch/arm/mm/copypage-v3.c
arch/arm/mm/copypage-v4mc.c
arch/arm/mm/copypage-v4wb.c
arch/arm/mm/copypage-v4wt.c
arch/arm/mm/copypage-v6.c
arch/arm/mm/copypage-xsc3.c
arch/arm/mm/copypage-xscale.c
arch/arm/mm/dma-mapping.c
arch/arm/mm/fault-armv.c
arch/arm/mm/fault.c
arch/arm/mm/flush.c
arch/arm/mm/init.c
arch/arm/mm/ioremap.c
arch/arm/mm/mmu.c
arch/arm/mm/nommu.c
arch/arm/mm/proc-arm1020.S
arch/arm/mm/proc-arm1020e.S
arch/arm/mm/proc-arm1022.S
arch/arm/mm/proc-arm1026.S
arch/arm/mm/proc-arm920.S
arch/arm/mm/proc-arm922.S
arch/arm/mm/proc-arm925.S
arch/arm/mm/proc-arm926.S
arch/arm/mm/proc-arm940.S
arch/arm/mm/proc-arm946.S
arch/arm/mm/proc-feroceon.S
arch/arm/mm/proc-mohawk.S
arch/arm/mm/proc-xsc3.S
arch/arm/mm/proc-xscale.S
arch/arm/oprofile/op_model_arm11_core.c
arch/arm/oprofile/op_model_arm11_core.h
arch/arm/oprofile/op_model_mpcore.c
arch/arm/oprofile/op_model_v6.c
arch/arm/oprofile/op_model_v7.c
arch/arm/oprofile/op_model_v7.h
arch/arm/oprofile/op_model_xscale.c
arch/arm/plat-iop/io.c
arch/arm/plat-mxc/Makefile
arch/arm/plat-mxc/include/mach/debug-macro.S
arch/arm/plat-mxc/include/mach/vmalloc.h
arch/arm/plat-mxc/ssi-fiq-ksym.c [new file with mode: 0644]
arch/arm/plat-mxc/ssi-fiq.S [new file with mode: 0644]
arch/arm/plat-nomadik/include/plat/i2c.h [new file with mode: 0644]
arch/arm/plat-omap/Kconfig
arch/arm/plat-omap/include/plat/omap44xx.h
arch/arm/plat-omap/io.c
arch/arm/plat-s3c/include/mach/vmalloc.h
arch/arm/plat-stmp3xxx/clock.c
arch/arm/plat-stmp3xxx/include/mach/debug-macro.S
arch/arm/plat-stmp3xxx/include/mach/vmalloc.h
arch/arm/vfp/vfpmodule.c
arch/avr32/include/asm/pgtable.h
arch/avr32/mm/tlb.c
arch/cris/arch-v10/kernel/irq.c
arch/cris/arch-v32/kernel/irq.c
arch/cris/arch-v32/kernel/pinmux.c
arch/cris/arch-v32/mach-a3/pinmux.c
arch/cris/arch-v32/mach-fs/pinmux.c
arch/cris/include/asm/pgtable.h
arch/cris/kernel/irq.c
arch/frv/include/asm/pgtable.h
arch/ia64/Kconfig
arch/ia64/Makefile
arch/ia64/configs/bigsur_defconfig
arch/ia64/configs/generic_defconfig
arch/ia64/configs/gensparse_defconfig
arch/ia64/configs/sim_defconfig
arch/ia64/configs/tiger_defconfig
arch/ia64/configs/xen_domu_defconfig
arch/ia64/configs/zx1_defconfig
arch/ia64/hp/common/aml_nfw.c
arch/ia64/ia32/Makefile [deleted file]
arch/ia64/ia32/audit.c [deleted file]
arch/ia64/ia32/binfmt_elf32.c [deleted file]
arch/ia64/ia32/elfcore32.h [deleted file]
arch/ia64/ia32/ia32_entry.S [deleted file]
arch/ia64/ia32/ia32_ldt.c [deleted file]
arch/ia64/ia32/ia32_signal.c [deleted file]
arch/ia64/ia32/ia32_support.c [deleted file]
arch/ia64/ia32/ia32_traps.c [deleted file]
arch/ia64/ia32/ia32priv.h [deleted file]
arch/ia64/ia32/sys_ia32.c [deleted file]
arch/ia64/include/asm/acpi.h
arch/ia64/include/asm/ia32.h [deleted file]
arch/ia64/include/asm/pgtable.h
arch/ia64/include/asm/processor.h
arch/ia64/include/asm/scatterlist.h
arch/ia64/include/asm/syscall.h
arch/ia64/include/asm/system.h
arch/ia64/include/asm/unistd.h
arch/ia64/kernel/Makefile
arch/ia64/kernel/acpi.c
arch/ia64/kernel/audit.c
arch/ia64/kernel/entry.S
arch/ia64/kernel/ivt.S
arch/ia64/kernel/perfmon.c
arch/ia64/kernel/process.c
arch/ia64/kernel/ptrace.c
arch/ia64/kernel/setup.c
arch/ia64/kernel/signal.c
arch/ia64/kernel/smpboot.c
arch/ia64/kernel/time.c
arch/ia64/kernel/traps.c
arch/ia64/mm/init.c
arch/ia64/uv/kernel/setup.c
arch/ia64/xen/hypercall.S
arch/ia64/xen/xen_pv_ops.c
arch/m32r/include/asm/tlbflush.h
arch/m32r/mm/fault-nommu.c
arch/m32r/mm/fault.c
arch/m68k/include/asm/pgtable_mm.h
arch/microblaze/include/asm/tlbflush.h
arch/mips/include/asm/pgtable.h
arch/mn10300/include/asm/pgtable.h
arch/mn10300/mm/mmu-context.c
arch/parisc/include/asm/pgtable.h
arch/parisc/kernel/cache.c
arch/powerpc/include/asm/pgtable.h
arch/powerpc/mm/mem.c
arch/s390/include/asm/pgtable.h
arch/score/include/asm/pgtable.h
arch/sh/include/asm/pgtable.h
arch/sh/include/asm/siu.h [new file with mode: 0644]
arch/sh/mm/fault_32.c
arch/sparc/include/asm/pgtable_32.h
arch/sparc/include/asm/pgtable_64.h
arch/sparc/mm/fault_32.c
arch/sparc/mm/init_64.c
arch/sparc/mm/nosun4c.c
arch/sparc/mm/srmmu.c
arch/sparc/mm/sun4c.c
arch/um/drivers/ubd_kern.c
arch/um/include/asm/pgtable.h
arch/x86/include/asm/pgtable_32.h
arch/x86/include/asm/pgtable_64.h
arch/x86/kernel/cpu/cpufreq/powernow-k8.c
arch/x86/kernel/hpet.c
arch/x86/kernel/tsc.c
arch/xtensa/include/asm/pgtable.h
arch/xtensa/mm/cache.c
block/blk-cgroup.c
block/blk-cgroup.h
block/blk-core.c
block/blk-ioc.c
block/blk-merge.c
block/blk-settings.c
block/blk-sysfs.c
block/cfq-iosched.c
block/elevator.c
drivers/acpi/acpica/accommon.h
drivers/acpi/acpica/acconfig.h
drivers/acpi/acpica/acdebug.h
drivers/acpi/acpica/acdispat.h
drivers/acpi/acpica/acevents.h
drivers/acpi/acpica/acglobal.h
drivers/acpi/acpica/achware.h
drivers/acpi/acpica/acinterp.h
drivers/acpi/acpica/aclocal.h
drivers/acpi/acpica/acmacros.h
drivers/acpi/acpica/acnamesp.h
drivers/acpi/acpica/acobject.h
drivers/acpi/acpica/acopcode.h
drivers/acpi/acpica/acparser.h
drivers/acpi/acpica/acpredef.h
drivers/acpi/acpica/acresrc.h
drivers/acpi/acpica/acstruct.h
drivers/acpi/acpica/actables.h
drivers/acpi/acpica/acutils.h
drivers/acpi/acpica/amlcode.h
drivers/acpi/acpica/amlresrc.h
drivers/acpi/acpica/dsfield.c
drivers/acpi/acpica/dsinit.c
drivers/acpi/acpica/dsmethod.c
drivers/acpi/acpica/dsmthdat.c
drivers/acpi/acpica/dsobject.c
drivers/acpi/acpica/dsopcode.c
drivers/acpi/acpica/dsutils.c
drivers/acpi/acpica/dswexec.c
drivers/acpi/acpica/dswload.c
drivers/acpi/acpica/dswscope.c
drivers/acpi/acpica/dswstate.c
drivers/acpi/acpica/evevent.c
drivers/acpi/acpica/evgpe.c
drivers/acpi/acpica/evgpeblk.c
drivers/acpi/acpica/evmisc.c
drivers/acpi/acpica/evregion.c
drivers/acpi/acpica/evrgnini.c
drivers/acpi/acpica/evsci.c
drivers/acpi/acpica/evxface.c
drivers/acpi/acpica/evxfevnt.c
drivers/acpi/acpica/evxfregn.c
drivers/acpi/acpica/exconfig.c
drivers/acpi/acpica/exconvrt.c
drivers/acpi/acpica/excreate.c
drivers/acpi/acpica/exdump.c
drivers/acpi/acpica/exfield.c
drivers/acpi/acpica/exfldio.c
drivers/acpi/acpica/exmisc.c
drivers/acpi/acpica/exmutex.c
drivers/acpi/acpica/exnames.c
drivers/acpi/acpica/exoparg1.c
drivers/acpi/acpica/exoparg2.c
drivers/acpi/acpica/exoparg3.c
drivers/acpi/acpica/exoparg6.c
drivers/acpi/acpica/exprep.c
drivers/acpi/acpica/exregion.c
drivers/acpi/acpica/exresnte.c
drivers/acpi/acpica/exresolv.c
drivers/acpi/acpica/exresop.c
drivers/acpi/acpica/exstore.c
drivers/acpi/acpica/exstoren.c
drivers/acpi/acpica/exstorob.c
drivers/acpi/acpica/exsystem.c
drivers/acpi/acpica/exutils.c
drivers/acpi/acpica/hwacpi.c
drivers/acpi/acpica/hwgpe.c
drivers/acpi/acpica/hwregs.c
drivers/acpi/acpica/hwsleep.c
drivers/acpi/acpica/hwtimer.c
drivers/acpi/acpica/hwvalid.c
drivers/acpi/acpica/hwxface.c
drivers/acpi/acpica/nsaccess.c
drivers/acpi/acpica/nsalloc.c
drivers/acpi/acpica/nsdump.c
drivers/acpi/acpica/nsdumpdv.c
drivers/acpi/acpica/nseval.c
drivers/acpi/acpica/nsinit.c
drivers/acpi/acpica/nsload.c
drivers/acpi/acpica/nsnames.c
drivers/acpi/acpica/nsobject.c
drivers/acpi/acpica/nsparse.c
drivers/acpi/acpica/nspredef.c
drivers/acpi/acpica/nsrepair.c
drivers/acpi/acpica/nsrepair2.c
drivers/acpi/acpica/nssearch.c
drivers/acpi/acpica/nsutils.c
drivers/acpi/acpica/nswalk.c
drivers/acpi/acpica/nsxfeval.c
drivers/acpi/acpica/nsxfname.c
drivers/acpi/acpica/nsxfobj.c
drivers/acpi/acpica/psargs.c
drivers/acpi/acpica/psloop.c
drivers/acpi/acpica/psopcode.c
drivers/acpi/acpica/psparse.c
drivers/acpi/acpica/psscope.c
drivers/acpi/acpica/pstree.c
drivers/acpi/acpica/psutils.c
drivers/acpi/acpica/pswalk.c
drivers/acpi/acpica/psxface.c
drivers/acpi/acpica/rsaddr.c
drivers/acpi/acpica/rscalc.c
drivers/acpi/acpica/rscreate.c
drivers/acpi/acpica/rsdump.c
drivers/acpi/acpica/rsinfo.c
drivers/acpi/acpica/rsio.c
drivers/acpi/acpica/rsirq.c
drivers/acpi/acpica/rslist.c
drivers/acpi/acpica/rsmemory.c
drivers/acpi/acpica/rsmisc.c
drivers/acpi/acpica/rsutils.c
drivers/acpi/acpica/rsxface.c
drivers/acpi/acpica/tbfadt.c
drivers/acpi/acpica/tbfind.c
drivers/acpi/acpica/tbinstal.c
drivers/acpi/acpica/tbutils.c
drivers/acpi/acpica/tbxface.c
drivers/acpi/acpica/tbxfroot.c
drivers/acpi/acpica/utalloc.c
drivers/acpi/acpica/utcopy.c
drivers/acpi/acpica/utdebug.c
drivers/acpi/acpica/utdelete.c
drivers/acpi/acpica/uteval.c
drivers/acpi/acpica/utglobal.c
drivers/acpi/acpica/utids.c
drivers/acpi/acpica/utinit.c
drivers/acpi/acpica/utlock.c
drivers/acpi/acpica/utmath.c
drivers/acpi/acpica/utmisc.c
drivers/acpi/acpica/utmutex.c
drivers/acpi/acpica/utobject.c
drivers/acpi/acpica/utresrc.c
drivers/acpi/acpica/utstate.c
drivers/acpi/acpica/utxface.c
drivers/acpi/battery.c
drivers/acpi/ec.c
drivers/acpi/glue.c
drivers/acpi/osl.c
drivers/acpi/power_meter.c
drivers/acpi/processor_idle.c
drivers/acpi/processor_throttling.c
drivers/acpi/utils.c
drivers/acpi/video.c
drivers/ata/Kconfig
drivers/ata/ahci.c
drivers/ata/ata_generic.c
drivers/ata/ata_piix.c
drivers/ata/libata-acpi.c
drivers/ata/libata-core.c
drivers/ata/libata-scsi.c
drivers/ata/libata-sff.c
drivers/ata/pata_acpi.c
drivers/ata/pata_ali.c
drivers/ata/pata_amd.c
drivers/ata/pata_artop.c
drivers/ata/pata_at91.c
drivers/ata/pata_atiixp.c
drivers/ata/pata_cmd640.c
drivers/ata/pata_cmd64x.c
drivers/ata/pata_cs5530.c
drivers/ata/pata_cs5535.c
drivers/ata/pata_cs5536.c
drivers/ata/pata_cypress.c
drivers/ata/pata_efar.c
drivers/ata/pata_hpt366.c
drivers/ata/pata_hpt37x.c
drivers/ata/pata_hpt3x2n.c
drivers/ata/pata_it8213.c
drivers/ata/pata_it821x.c
drivers/ata/pata_jmicron.c
drivers/ata/pata_marvell.c
drivers/ata/pata_netcell.c
drivers/ata/pata_ns87410.c
drivers/ata/pata_ns87415.c
drivers/ata/pata_oldpiix.c
drivers/ata/pata_opti.c
drivers/ata/pata_optidma.c
drivers/ata/pata_pcmcia.c
drivers/ata/pata_pdc202xx_old.c
drivers/ata/pata_piccolo.c
drivers/ata/pata_radisys.c
drivers/ata/pata_rz1000.c
drivers/ata/pata_sc1200.c
drivers/ata/pata_serverworks.c
drivers/ata/pata_sil680.c
drivers/ata/pata_sis.c
drivers/ata/pata_sl82c105.c
drivers/ata/pata_triflex.c
drivers/ata/pata_via.c
drivers/ata/sata_nv.c
drivers/ata/sata_via.c
drivers/block/DAC960.c
drivers/block/brd.c
drivers/block/cciss.c
drivers/block/cciss.h
drivers/block/cciss_cmd.h
drivers/block/cciss_scsi.c
drivers/block/cciss_scsi.h
drivers/block/cpqarray.c
drivers/block/drbd/drbd_nl.c
drivers/block/floppy.c
drivers/block/hd.c
drivers/block/mg_disk.c
drivers/block/paride/pd.c
drivers/block/paride/pf.c
drivers/block/pktcdvd.c
drivers/block/ps3disk.c
drivers/block/ps3vram.c
drivers/block/sunvdc.c
drivers/block/sx8.c
drivers/block/ub.c
drivers/block/viodasd.c
drivers/block/virtio_blk.c
drivers/block/xd.c
drivers/block/xen-blkfront.c
drivers/block/xsysace.c
drivers/cdrom/gdrom.c
drivers/cdrom/viocd.c
drivers/char/keyboard.c
drivers/char/nvram.c
drivers/clocksource/sh_cmt.c
drivers/firewire/sbp2.c
drivers/i2c/busses/i2c-pnx.c
drivers/ide/ide-acpi.c
drivers/ide/ide-disk.c
drivers/ide/ide-floppy.c
drivers/ide/ide-probe.c
drivers/ieee1394/sbp2.c
drivers/input/evdev.c
drivers/input/gameport/emu10k1-gp.c
drivers/input/gameport/fm801-gp.c
drivers/input/gameport/gameport.c
drivers/input/gameport/ns558.c
drivers/input/input-compat.h
drivers/input/input.c
drivers/input/joydev.c
drivers/input/joystick/Kconfig
drivers/input/joystick/gamecon.c
drivers/input/joystick/xpad.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
drivers/input/keyboard/adp5588-keys.c
drivers/input/keyboard/atkbd.c
drivers/input/keyboard/ep93xx_keypad.c
drivers/input/keyboard/gpio_keys.c
drivers/input/keyboard/imx_keypad.c [new file with mode: 0644]
drivers/input/keyboard/qt2160.c
drivers/input/keyboard/sh_keysc.c
drivers/input/misc/apanel.c
drivers/input/misc/atlas_btns.c
drivers/input/misc/rotary_encoder.c
drivers/input/misc/uinput.c
drivers/input/misc/winbond-cir.c
drivers/input/mouse/hgpk.c
drivers/input/serio/pcips2.c
drivers/input/serio/serio.c
drivers/input/serio/xilinx_ps2.c
drivers/input/tablet/gtco.c
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/ads7846.c
drivers/input/touchscreen/elo.c
drivers/input/touchscreen/mainstone-wm97xx.c
drivers/input/touchscreen/s3c2410_ts.c
drivers/input/touchscreen/tsc2007.c
drivers/input/touchscreen/usbtouchscreen.c
drivers/input/touchscreen/zylonite-wm97xx.c
drivers/input/xen-kbdfront.c
drivers/macintosh/Kconfig
drivers/macintosh/mac_hid.c
drivers/md/linear.c
drivers/md/multipath.c
drivers/md/raid0.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid5.c
drivers/memstick/core/mspro_block.c
drivers/message/i2o/i2o_block.c
drivers/mfd/twl-core.c
drivers/mmc/card/queue.c
drivers/mmc/host/mmci.c
drivers/net/Kconfig
drivers/net/davinci_emac.c
drivers/pci/pci-acpi.c
drivers/pci/setup-bus.c
drivers/platform/x86/toshiba_bluetooth.c
drivers/platform/x86/wmi.c
drivers/rtc/rtc-pl031.c
drivers/s390/block/dasd.c
drivers/s390/char/tape_block.c
drivers/scsi/ibmvscsi/ibmvfc.c
drivers/scsi/ipr.c
drivers/scsi/pmcraid.c
drivers/scsi/scsi.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_scan.c
drivers/scsi/sg.c
drivers/scsi/st.c
drivers/serial/amba-pl011.c
drivers/spi/amba-pl022.c
drivers/staging/hv/blkvsc_drv.c
drivers/staging/phison/phison.c
drivers/usb/gadget/f_audio.c
drivers/usb/gadget/gmidi.c
drivers/usb/storage/scsiglue.c
drivers/virtio/virtio_pci.c
drivers/watchdog/pnx4008_wdt.c
fs/bio.c
fs/partitions/check.c
include/acpi/acexcep.h
include/acpi/acnames.h
include/acpi/acoutput.h
include/acpi/acpi.h
include/acpi/acpi_bus.h
include/acpi/acpiosxf.h
include/acpi/acpixf.h
include/acpi/acrestyp.h
include/acpi/actbl.h
include/acpi/actbl1.h
include/acpi/actbl2.h
include/acpi/actypes.h
include/acpi/platform/acenv.h
include/acpi/platform/acgcc.h
include/acpi/platform/aclinux.h
include/acpi/processor.h
include/linux/Kbuild
include/linux/ata.h
include/linux/blkdev.h
include/linux/cciss_defs.h [new file with mode: 0644]
include/linux/cciss_ioctl.h
include/linux/clocksource.h
include/linux/davinci_emac.h [moved from arch/arm/mach-davinci/include/mach/emac.h with 83% similarity]
include/linux/gameport.h
include/linux/gpio_keys.h
include/linux/i2c-pnx.h
include/linux/i2c/twl.h
include/linux/i2o.h
include/linux/input.h
include/linux/input/sh_keysc.h
include/linux/iocontext.h
include/linux/irq.h
include/linux/kbd_kern.h
include/linux/libata.h
include/linux/pktcdvd.h
include/linux/sched.h
include/linux/serio.h
include/linux/timex.h
include/linux/usb/audio.h
include/sound/core.h
include/sound/cs46xx_dsp_spos.h
include/sound/pcm.h
include/sound/pcm_oss.h
include/sound/sb.h
include/sound/soc-dai.h
include/sound/soc-dapm.h
include/sound/soc.h
include/sound/tlv320dac33-plat.h
include/sound/tpa6130a2-plat.h
include/sound/version.h
include/sound/wm2000.h [new file with mode: 0644]
include/sound/wm8904.h [new file with mode: 0644]
include/sound/wm8955.h [new file with mode: 0644]
kernel/futex_compat.c
kernel/posix-timers.c
kernel/time/clocksource.c
kernel/time/ntp.c
kernel/time/timekeeping.c
kernel/trace/blktrace.c
mm/hugetlb.c
mm/memory.c
mm/migrate.c
sound/core/control.c
sound/core/misc.c
sound/core/oss/pcm_oss.c
sound/core/pcm.c
sound/core/pcm_lib.c
sound/core/pcm_memory.c
sound/core/pcm_native.c
sound/core/seq/seq_clientmgr.c
sound/core/seq/seq_timer.c
sound/drivers/dummy.c
sound/drivers/vx/vx_pcm.c
sound/isa/Kconfig
sound/isa/Makefile
sound/isa/als100.c
sound/isa/dt019x.c [deleted file]
sound/isa/opti9xx/opti92x-ad1848.c
sound/isa/sb/Makefile
sound/isa/sb/jazz16.c [new file with mode: 0644]
sound/isa/sb/sb8_main.c
sound/isa/sb/sb_common.c
sound/isa/sb/sb_mixer.c
sound/isa/wss/wss_lib.c
sound/mips/sgio2audio.c
sound/oss/kahlua.c
sound/oss/soundcard.c
sound/pci/Kconfig
sound/pci/ac97/ac97_patch.c
sound/pci/ad1889.c
sound/pci/ali5451/ali5451.c
sound/pci/als300.c
sound/pci/als4000.c
sound/pci/atiixp.c
sound/pci/atiixp_modem.c
sound/pci/au88x0/au8810.c
sound/pci/au88x0/au8820.c
sound/pci/au88x0/au8830.c
sound/pci/aw2/aw2-alsa.c
sound/pci/azt3328.c
sound/pci/bt87x.c
sound/pci/ca0106/ca0106_main.c
sound/pci/cmipci.c
sound/pci/cs4281.c
sound/pci/cs46xx/cs46xx.c
sound/pci/cs46xx/cs46xx_lib.c
sound/pci/cs46xx/dsp_spos.c
sound/pci/cs46xx/dsp_spos.h
sound/pci/cs46xx/dsp_spos_scb_lib.c
sound/pci/cs5530.c
sound/pci/cs5535audio/cs5535audio.c
sound/pci/ctxfi/ctatc.c
sound/pci/ctxfi/ctatc.h
sound/pci/ctxfi/xfi.c
sound/pci/echoaudio/darla20.c
sound/pci/echoaudio/darla20_dsp.c
sound/pci/echoaudio/darla24.c
sound/pci/echoaudio/darla24_dsp.c
sound/pci/echoaudio/echo3g.c
sound/pci/echoaudio/echo3g_dsp.c
sound/pci/echoaudio/echoaudio.c
sound/pci/echoaudio/echoaudio.h
sound/pci/echoaudio/echoaudio_3g.c
sound/pci/echoaudio/echoaudio_dsp.c
sound/pci/echoaudio/gina20.c
sound/pci/echoaudio/gina20_dsp.c
sound/pci/echoaudio/gina24.c
sound/pci/echoaudio/gina24_dsp.c
sound/pci/echoaudio/indigo.c
sound/pci/echoaudio/indigo_dsp.c
sound/pci/echoaudio/indigo_express_dsp.c
sound/pci/echoaudio/indigodj.c
sound/pci/echoaudio/indigodj_dsp.c
sound/pci/echoaudio/indigodjx.c
sound/pci/echoaudio/indigodjx_dsp.c
sound/pci/echoaudio/indigoio.c
sound/pci/echoaudio/indigoio_dsp.c
sound/pci/echoaudio/indigoiox.c
sound/pci/echoaudio/indigoiox_dsp.c
sound/pci/echoaudio/layla20.c
sound/pci/echoaudio/layla20_dsp.c
sound/pci/echoaudio/layla24.c
sound/pci/echoaudio/layla24_dsp.c
sound/pci/echoaudio/mia.c
sound/pci/echoaudio/mia_dsp.c
sound/pci/echoaudio/mona.c
sound/pci/echoaudio/mona_dsp.c
sound/pci/emu10k1/emu10k1.c
sound/pci/emu10k1/emu10k1x.c
sound/pci/ens1370.c
sound/pci/es1938.c
sound/pci/es1968.c
sound/pci/fm801.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_hwdep.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_local.h
sound/pci/hda/hda_proc.c
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_cmedia.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_si3054.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c
sound/pci/ice1712/ice1712.c
sound/pci/ice1712/ice1724.c
sound/pci/intel8x0.c
sound/pci/intel8x0m.c
sound/pci/korg1212/korg1212.c
sound/pci/lx6464es/lx6464es.c
sound/pci/maestro3.c
sound/pci/mixart/mixart.c
sound/pci/nm256/nm256.c
sound/pci/oxygen/Makefile
sound/pci/oxygen/hifier.c
sound/pci/oxygen/oxygen.c
sound/pci/oxygen/virtuoso.c
sound/pci/oxygen/wm8766.h [new file with mode: 0644]
sound/pci/oxygen/wm8776.h [new file with mode: 0644]
sound/pci/oxygen/xonar.h
sound/pci/oxygen/xonar_wm87x6.c [new file with mode: 0644]
sound/pci/pcxhr/pcxhr.c
sound/pci/riptide/riptide.c
sound/pci/rme32.c
sound/pci/rme96.c
sound/pci/rme9652/hdsp.c
sound/pci/rme9652/hdspm.c
sound/pci/rme9652/rme9652.c
sound/pci/sis7019.c
sound/pci/sonicvibes.c
sound/pci/trident/trident.c
sound/pci/via82xx.c
sound/pci/via82xx_modem.c
sound/pci/vx222/vx222.c
sound/pci/ymfpci/ymfpci.c
sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c
sound/soc/blackfin/bf5xx-ac97-pcm.c
sound/soc/blackfin/bf5xx-i2s-pcm.c
sound/soc/blackfin/bf5xx-tdm-pcm.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ad1836.c
sound/soc/codecs/ad1836.h
sound/soc/codecs/ad1938.c
sound/soc/codecs/ak4104.c
sound/soc/codecs/cs4270.c
sound/soc/codecs/da7210.c [new file with mode: 0644]
sound/soc/codecs/da7210.h [new file with mode: 0644]
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/tlv320dac33.c
sound/soc/codecs/tpa6130a2.c
sound/soc/codecs/twl4030.c
sound/soc/codecs/twl4030.h
sound/soc/codecs/wm2000.c [new file with mode: 0644]
sound/soc/codecs/wm2000.h [new file with mode: 0644]
sound/soc/codecs/wm8727.c
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8753.c
sound/soc/codecs/wm8776.c
sound/soc/codecs/wm8904.c [new file with mode: 0644]
sound/soc/codecs/wm8904.h [new file with mode: 0644]
sound/soc/codecs/wm8955.c [new file with mode: 0644]
sound/soc/codecs/wm8955.h [new file with mode: 0644]
sound/soc/codecs/wm8961.c
sound/soc/codecs/wm8974.c
sound/soc/codecs/wm8974.h
sound/soc/codecs/wm8978.c [new file with mode: 0644]
sound/soc/codecs/wm8978.h [new file with mode: 0644]
sound/soc/codecs/wm8990.c
sound/soc/codecs/wm8993.c
sound/soc/codecs/wm8994.c [new file with mode: 0644]
sound/soc/codecs/wm8994.h [new file with mode: 0644]
sound/soc/codecs/wm9713.c
sound/soc/codecs/wm_hubs.c
sound/soc/codecs/wm_hubs.h
sound/soc/davinci/davinci-mcasp.c
sound/soc/davinci/davinci-mcasp.h
sound/soc/davinci/davinci-pcm.c
sound/soc/imx/Kconfig
sound/soc/imx/Makefile
sound/soc/imx/imx-pcm-dma-mx2.c [new file with mode: 0644]
sound/soc/imx/imx-pcm-fiq.c [new file with mode: 0644]
sound/soc/imx/imx-ssi.c [new file with mode: 0644]
sound/soc/imx/imx-ssi.h [new file with mode: 0644]
sound/soc/imx/mx1_mx2-pcm.c [deleted file]
sound/soc/imx/mx1_mx2-pcm.h [deleted file]
sound/soc/imx/mx27vis_wm8974.c [deleted file]
sound/soc/imx/mxc-ssi.c [deleted file]
sound/soc/imx/mxc-ssi.h [deleted file]
sound/soc/imx/phycore-ac97.c [new file with mode: 0644]
sound/soc/omap/Kconfig
sound/soc/omap/Makefile
sound/soc/omap/mcpdm.c [new file with mode: 0644]
sound/soc/omap/mcpdm.h [new file with mode: 0644]
sound/soc/omap/omap-mcbsp.c
sound/soc/omap/omap-mcpdm.c [new file with mode: 0644]
sound/soc/omap/omap-mcpdm.h [new file with mode: 0644]
sound/soc/omap/omap-pcm.c
sound/soc/omap/omap-pcm.h
sound/soc/omap/omap3beagle.c
sound/soc/omap/omap3pandora.c
sound/soc/pxa/pxa-ssp.c
sound/soc/pxa/raumfeld.c
sound/soc/s3c24xx/Kconfig
sound/soc/s3c24xx/Makefile
sound/soc/s3c24xx/ln2440sbc_alc650.c
sound/soc/s3c24xx/s3c-ac97.c [new file with mode: 0644]
sound/soc/s3c24xx/s3c-ac97.h [new file with mode: 0644]
sound/soc/s3c24xx/s3c-pcm.c
sound/soc/s3c24xx/s3c2443-ac97.c [deleted file]
sound/soc/s3c24xx/s3c24xx-ac97.h [deleted file]
sound/soc/s3c24xx/s3c64xx-i2s.c
sound/soc/s3c24xx/smdk2443_wm9710.c
sound/soc/s3c24xx/smdk_wm9713.c [new file with mode: 0644]
sound/soc/sh/Kconfig
sound/soc/sh/Makefile
sound/soc/sh/fsi-da7210.c [new file with mode: 0644]
sound/soc/sh/fsi.c
sound/soc/sh/migor.c [new file with mode: 0644]
sound/soc/sh/siu.h [new file with mode: 0644]
sound/soc/sh/siu_dai.c [new file with mode: 0644]
sound/soc/sh/siu_pcm.c [new file with mode: 0644]
sound/soc/soc-cache.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/usb/Kconfig
sound/usb/Makefile
sound/usb/ua101.c [new file with mode: 0644]
sound/usb/usbaudio.c
sound/usb/usbaudio.h
sound/usb/usbmidi.c
sound/usb/usbmixer.c
sound/usb/usbmixer_maps.c
sound/usb/usbquirks.h
sound/usb/usx2y/us122l.c

index d2f90334bb93f90af2986e96d3cfd9710180eca7..4873c759d535a7549d5eecf62a7125b29d6c2dea 100644 (file)
@@ -128,3 +128,17 @@ Description:
                preferred request size for workloads where sustained
                throughput is desired.  If no optimal I/O size is
                reported this file contains 0.
+
+What:          /sys/block/<disk>/queue/nomerges
+Date:          January 2010
+Contact:
+Description:
+               Standard I/O elevator operations include attempts to
+               merge contiguous I/Os. For known random I/O loads these
+               attempts will always fail and result in extra cycles
+               being spent in the kernel. This allows one to turn off
+               this behavior on one of two ways: When set to 1, complex
+               merge checks are disabled, but the simple one-shot merges
+               with the previous I/O request are enabled. When set to 2,
+               all merge tries are disabled. The default value is 0 -
+               which enables all types of merge tries.
index 9d58c7c5eddd082b9a22c087c7e0023e02fa4b02..eb0fae18ffb12a805bb81eb2c5005a773d499d2b 100644 (file)
@@ -59,7 +59,11 @@ PAGE_OFFSET  high_memory-1   Kernel direct-mapped RAM region.
                                This maps the platforms RAM, and typically
                                maps all platform RAM in a 1:1 relationship.
 
-TASK_SIZE      PAGE_OFFSET-1   Kernel module space
+PKMAP_BASE     PAGE_OFFSET-1   Permanent kernel mappings
+                               One way of mapping HIGHMEM pages into kernel
+                               space.
+
+MODULES_VADDR  MODULES_END-1   Kernel module space
                                Kernel modules inserted via insmod are
                                placed here using dynamic mappings.
 
index e164403f60e19b92e01050b3800826acbe27448a..f65274081c8d19a1c2f6f8b53712a1cf9cbee54d 100644 (file)
@@ -25,11 +25,11 @@ size allowed by the hardware.
 
 nomerges (RW)
 -------------
-This enables the user to disable the lookup logic involved with IO merging
-requests in the block layer. Merging may still occur through a direct
-1-hit cache, since that comes for (almost) free. The IO scheduler will not
-waste cycles doing tree/hash lookups for merges if nomerges is 1. Defaults
-to 0, enabling all merges.
+This enables the user to disable the lookup logic involved with IO
+merging requests in the block layer. By default (0) all merges are
+enabled. When set to 1 only simple one-hit merges will be tried. When
+set to 2 no merge algorithms will be tried (including one-hit or more
+complex tree/hash lookups).
 
 nr_requests (RW)
 ----------------
index b231414bb8bc4b84d218fc2f2f75d5665d0a0761..2b5f823abd035fd180d94732c523671378c2ef9d 100644 (file)
@@ -88,12 +88,12 @@ changes occur:
        This is used primarily during fault processing.
 
 5) void update_mmu_cache(struct vm_area_struct *vma,
-                        unsigned long address, pte_t pte)
+                        unsigned long address, pte_t *ptep)
 
        At the end of every page fault, this routine is invoked to
        tell the architecture specific code that a translation
-       described by "pte" now exists at virtual address "address"
-       for address space "vma->vm_mm", in the software page tables.
+       now exists at virtual address "address" for address space
+       "vma->vm_mm", in the software page tables.
 
        A port may use this information in any way it so chooses.
        For example, it could use this event to pre-load TLB
index a0a4fd43e62de1a5a4819492389ec9584d7144ec..73ef30dbe61263e4697bba21dec15c31d649d2b1 100644 (file)
@@ -520,6 +520,29 @@ Who:       Hans de Goede <hdegoede@redhat.com>
 
 ----------------------------
 
+What:  corgikbd, spitzkbd, tosakbd driver
+When:  2.6.35
+Files: drivers/input/keyboard/{corgi,spitz,tosa}kbd.c
+Why:   We now have a generic GPIO based matrix keyboard driver that
+       are fully capable of handling all the keys on these devices.
+       The original drivers manipulate the GPIO registers directly
+       and so are difficult to maintain.
+Who:   Eric Miao <eric.y.miao@gmail.com>
+
+----------------------------
+
+What:  corgi_ssp and corgi_ts driver
+When:  2.6.35
+Files: arch/arm/mach-pxa/corgi_ssp.c, drivers/input/touchscreen/corgi_ts.c
+Why:   The corgi touchscreen is now deprecated in favour of the generic
+       ads7846.c driver. The noise reduction technique used in corgi_ts.c,
+       that's to wait till vsync before ADC sampling, is also integrated into
+       ads7846 driver now. Provided that the original driver is not generic
+       and is difficult to maintain, it will be removed later.
+Who:   Eric Miao <eric.y.miao@gmail.com>
+
+----------------------------
+
 What:  capifs
 When:  February 2011
 Files: drivers/isdn/capi/capifs.*
index f7160a2fb6a2c91dfb61362362268c50c5b9033a..b35affd5c6496353dbb8e95398f89078671a2efa 100644 (file)
@@ -1,5 +1,5 @@
-Copyright (C) 2002-2008 Sentelic Corporation.
-Last update: Oct-31-2008
+Copyright (C) 2002-2010 Sentelic Corporation.
+Last update: Jan-13-2010
 
 ==============================================================================
 * Finger Sensing Pad Intellimouse Mode(scrolling wheel, 4th and 5th buttons)
@@ -44,7 +44,7 @@ B) MSID 6: Horizontal and Vertical scrolling.
 Packet 1
    Bit 7 6 5 4 3 2 1 0       7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0
 BYTE  |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------|
-  1   |Y|X|y|x|1|M|R|L|  2  |X|X|X|X|X|X|X|X|  3 |Y|Y|Y|Y|Y|Y|Y|Y|  4 | | |B|F|l|r|u|d|
+  1   |Y|X|y|x|1|M|R|L|  2  |X|X|X|X|X|X|X|X|  3 |Y|Y|Y|Y|Y|Y|Y|Y|  4 | | |B|F|r|l|u|d|
       |---------------|     |---------------|    |---------------|    |---------------|
 
 Byte 1: Bit7 => Y overflow
@@ -59,15 +59,15 @@ Byte 2: X Movement(9-bit 2's complement integers)
 Byte 3: Y Movement(9-bit 2's complement integers)
 Byte 4: Bit0 => the Vertical scrolling movement downward.
        Bit1 => the Vertical scrolling movement upward.
-       Bit2 => the Vertical scrolling movement rightward.
-       Bit3 => the Vertical scrolling movement leftward.
+       Bit2 => the Horizontal scrolling movement leftward.
+       Bit3 => the Horizontal scrolling movement rightward.
         Bit4 => 1 = 4th mouse button is pressed, Forward one page.
                 0 = 4th mouse button is not pressed.
         Bit5 => 1 = 5th mouse button is pressed, Backward one page.
                 0 = 5th mouse button is not pressed.
 
 C) MSID 7:
-# FSP uses 2 packets(8 Bytes) data to represent Absolute Position
+# FSP uses 2 packets (8 Bytes) to represent Absolute Position.
   so we have PACKET NUMBER to identify packets.
   If PACKET NUMBER is 0, the packet is Packet 1.
   If PACKET NUMBER is 1, the packet is Packet 2.
@@ -129,7 +129,7 @@ Byte 3: Message Type => 0x00 (Disabled)
 Byte 4: Bit7~Bit0 => Don't Care
 
 ==============================================================================
-* Absolute position for STL3888-A0.
+* Absolute position for STL3888-Ax.
 ==============================================================================
 Packet 1 (ABSOLUTE POSITION)
    Bit 7 6 5 4 3 2 1 0       7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0
@@ -179,14 +179,14 @@ Byte 4: Bit1~Bit0 => Y coordinate (xpos[1:0])
         Bit5~Bit4 => y2_g
         Bit7~Bit6 => x2_g
 
-Notify Packet for STL3888-A0
+Notify Packet for STL3888-Ax
    Bit 7 6 5 4 3 2 1 0       7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0
 BYTE  |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------|
   1   |1|0|1|P|1|M|R|L|  2  |C|C|C|C|C|C|C|C|  3 |0|0|F|F|0|0|0|i|  4 |r|l|d|u|0|0|0|0|
       |---------------|     |---------------|    |---------------|    |---------------|
 
 Byte 1: Bit7~Bit6 => 00, Normal data packet
-                  => 01, Absolute coordination packet
+                  => 01, Absolute coordinates packet
                   => 10, Notify packet
         Bit5 => 1
         Bit4 => when in absolute coordinates mode (valid when EN_PKT_GO is 1):
@@ -205,15 +205,106 @@ Byte 4: Bit7 => scroll right button
         Bit6 => scroll left button
         Bit5 => scroll down button
         Bit4 => scroll up button
-            * Note that if gesture and additional button (Bit4~Bit7)
-             happen at the same time, the button information will not
-             be sent.
+            * Note that if gesture and additional buttoni (Bit4~Bit7)
+              happen at the same time, the button information will not
+              be sent.
+        Bit3~Bit0 => Reserved
+
+Sample sequence of Multi-finger, Multi-coordinate mode:
+
+       notify packet (valid bit == 1), abs pkt 1, abs pkt 2, abs pkt 1,
+       abs pkt 2, ..., notify packet (valid bit == 0)
+
+==============================================================================
+* Absolute position for STL3888-B0.
+==============================================================================
+Packet 1(ABSOLUTE POSITION)
+   Bit 7 6 5 4 3 2 1 0       7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0
+BYTE  |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------|
+  1   |0|1|V|F|1|0|R|L|  2  |X|X|X|X|X|X|X|X|  3 |Y|Y|Y|Y|Y|Y|Y|Y|  4 |r|l|u|d|X|X|Y|Y|
+      |---------------|     |---------------|    |---------------|    |---------------|
+
+Byte 1: Bit7~Bit6 => 00, Normal data packet
+                  => 01, Absolute coordinates packet
+                  => 10, Notify packet
+        Bit5 => Valid bit, 0 means that the coordinate is invalid or finger up.
+                When both fingers are up, the last two reports have zero valid
+                bit.
+        Bit4 => finger up/down information. 1: finger down, 0: finger up.
+        Bit3 => 1
+        Bit2 => finger index, 0 is the first finger, 1 is the second finger.
+        Bit1 => Right Button, 1 is pressed, 0 is not pressed.
+        Bit0 => Left Button, 1 is pressed, 0 is not pressed.
+Byte 2: X coordinate (xpos[9:2])
+Byte 3: Y coordinate (ypos[9:2])
+Byte 4: Bit1~Bit0 => Y coordinate (xpos[1:0])
+        Bit3~Bit2 => X coordinate (ypos[1:0])
+        Bit4 => scroll down button
+        Bit5 => scroll up button
+        Bit6 => scroll left button
+        Bit7 => scroll right button
+
+Packet 2 (ABSOLUTE POSITION)
+   Bit 7 6 5 4 3 2 1 0       7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0
+BYTE  |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------|
+  1   |0|1|V|F|1|1|R|L|  2  |X|X|X|X|X|X|X|X|  3 |Y|Y|Y|Y|Y|Y|Y|Y|  4 |r|l|u|d|X|X|Y|Y|
+      |---------------|     |---------------|    |---------------|    |---------------|
+
+Byte 1: Bit7~Bit6 => 00, Normal data packet
+                  => 01, Absolute coordination packet
+                  => 10, Notify packet
+        Bit5 => Valid bit, 0 means that the coordinate is invalid or finger up.
+                When both fingers are up, the last two reports have zero valid
+                bit.
+        Bit4 => finger up/down information. 1: finger down, 0: finger up.
+        Bit3 => 1
+        Bit2 => finger index, 0 is the first finger, 1 is the second finger.
+        Bit1 => Right Button, 1 is pressed, 0 is not pressed.
+        Bit0 => Left Button, 1 is pressed, 0 is not pressed.
+Byte 2: X coordinate (xpos[9:2])
+Byte 3: Y coordinate (ypos[9:2])
+Byte 4: Bit1~Bit0 => Y coordinate (xpos[1:0])
+        Bit3~Bit2 => X coordinate (ypos[1:0])
+        Bit4 => scroll down button
+        Bit5 => scroll up button
+        Bit6 => scroll left button
+        Bit7 => scroll right button
+
+Notify Packet for STL3888-B0
+   Bit 7 6 5 4 3 2 1 0       7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0
+BYTE  |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------|
+  1   |1|0|1|P|1|M|R|L|  2  |C|C|C|C|C|C|C|C|  3 |0|0|F|F|0|0|0|i|  4 |r|l|u|d|0|0|0|0|
+      |---------------|     |---------------|    |---------------|    |---------------|
+
+Byte 1: Bit7~Bit6 => 00, Normal data packet
+                  => 01, Absolute coordination packet
+                  => 10, Notify packet
+        Bit5 => 1
+        Bit4 => when in absolute coordinate mode (valid when EN_PKT_GO is 1):
+                0: left button is generated by the on-pad command
+                1: left button is generated by the external button
+        Bit3 => 1
+        Bit2 => Middle Button, 1 is pressed, 0 is not pressed.
+        Bit1 => Right Button, 1 is pressed, 0 is not pressed.
+        Bit0 => Left Button, 1 is pressed, 0 is not pressed.
+Byte 2: Message Type => 0xB7 (Multi Finger, Multi Coordinate mode)
+Byte 3: Bit7~Bit6 => Don't care
+        Bit5~Bit4 => Number of fingers
+        Bit3~Bit1 => Reserved
+        Bit0 => 1: enter gesture mode; 0: leaving gesture mode
+Byte 4: Bit7 => scroll right button
+        Bit6 => scroll left button
+        Bit5 => scroll up button
+        Bit4 => scroll down button
+            * Note that if gesture and additional button(Bit4~Bit7)
+              happen at the same time, the button information will not
+              be sent.
         Bit3~Bit0 => Reserved
 
 Sample sequence of Multi-finger, Multi-coordinate mode:
 
        notify packet (valid bit == 1), abs pkt 1, abs pkt 2, abs pkt 1,
-       abs pkt 2, ..., notify packet(valid bit == 0)
+       abs pkt 2, ..., notify packet (valid bit == 0)
 
 ==============================================================================
 * FSP Enable/Disable packet
@@ -409,7 +500,8 @@ offset      width           default r/w     name
                                        0: read only, 1: read/write enable
        (Note that following registers does not require clock gating being
        enabled prior to write: 05 06 07 08 09 0c 0f 10 11 12 16 17 18 23 2e
-       40 41 42 43.)
+       40 41 42 43.  In addition to that, this bit must be 1 when gesture
+       mode is enabled)
 
 0x31                           RW      on-pad command detection
        bit7            0       RW      on-pad command left button down tag
@@ -463,6 +555,10 @@ offset     width           default r/w     name
        absolute coordinates; otherwise, host only receives packets with
        relative coordinate.)
 
+       bit7            0       RW      EN_PS2_F2: PS/2 gesture mode 2nd
+                                       finger packet enable
+                                       0: disable, 1: enable
+
 0x43                           RW      on-pad control
        bit0            0       RW      on-pad control enable
                                        0: disable, 1: enable
index 8923597bd2bd215a55ba00be57deca7339930bc1..33df82e3a3983a416c7750a273e6fdef734dbf0f 100644 (file)
@@ -482,6 +482,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     reference_rate     - reference sample rate, 44100 or 48000 (default)
     multiple           - multiple to ref. sample rate, 1 or 2 (default)
+    subsystem          - override the PCI SSID for probing; the value
+                         consists of SSVID << 16 | SSDID.  The default is
+                         zero, which means no override.
 
     This module supports multiple cards.
 
@@ -1123,6 +1126,21 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     This module supports multiple cards, autoprobe and ISA PnP.
 
+  Module snd-jazz16
+  -------------------
+
+    Module for Media Vision Jazz16 chipset. The chipset consists of 3 chips:
+    MVD1216 + MVA416 + MVA514.
+
+    port       - port # for SB DSP chip (0x210,0x220,0x230,0x240,0x250,0x260)
+    irq                - IRQ # for SB DSP chip (3,5,7,9,10,15)
+    dma8       - DMA # for SB DSP chip (1,3)
+    dma16      - DMA # for SB DSP chip (5,7)
+    mpu_port   - MPU-401 port # (0x300,0x310,0x320,0x330)
+    mpu_irq    - MPU-401 irq # (2,3,5,7)
+
+    This module supports multiple cards.
+
   Module snd-korg1212
   -------------------
 
@@ -1791,6 +1809,13 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     The power-management is supported.
 
+  Module snd-ua101
+  ----------------
+
+    Module for the Edirol UA-101 audio/MIDI interface.
+
+    This module supports multiple devices, autoprobe and hotplugging.
+
   Module snd-usb-audio
   --------------------
 
@@ -1923,7 +1948,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
   -------------------
 
     Module for sound cards based on the Asus AV100/AV200 chips,
-    i.e., Xonar D1, DX, D2, D2X, HDAV1.3 (Deluxe), Essence ST
+    i.e., Xonar D1, DX, D2, D2X, DS, HDAV1.3 (Deluxe), Essence ST
     (Deluxe) and Essence STX.
 
     This module supports autoprobe and multiple cards.
index e72cee9e2a71e72a5b99fc9a29668099ce667ae6..1d38b0dfba95f6138038716f215991c0f7fd6be9 100644 (file)
@@ -124,6 +124,8 @@ ALC882/883/885/888/889
   asus-a7m     ASUS A7M
   macpro       MacPro support
   mb5          Macbook 5,1
+  macmini3     Macmini 3,1
+  mba21                Macbook Air 2,1
   mbp3         Macbook Pro rev3
   imac24       iMac 24'' with jack detection
   imac91       iMac 9,1
@@ -279,13 +281,16 @@ Conexant 5051
   laptop       Basic Laptop config (default)
   hp           HP Spartan laptop
   hp-dv6736    HP dv6736
+  hp-f700      HP Compaq Presario F700
   lenovo-x200  Lenovo X200 laptop
+  toshiba      Toshiba Satellite M300
 
 Conexant 5066
 =============
   laptop       Basic Laptop config (default)
   dell-laptop  Dell laptops
   olpc-xo-1_5  OLPC XO 1.5
+  ideapad       Lenovo IdeaPad U150
 
 STAC9200
 ========
index 6325bec06a724e9a6fdad4f8b4028c34c3993c00..f4dd3bf99d126e01e2150b0623f8264baede76f3 100644 (file)
@@ -452,6 +452,33 @@ Similarly, the lines after `[verb]` are parsed as `init_verbs`
 sysfs entries, and the lines after `[hint]` are parsed as `hints`
 sysfs entries, respectively.
 
+Another example to override the codec vendor id from 0x12345678 to
+0xdeadbeef is like below:
+------------------------------------------------------------------------
+  [codec]
+  0x12345678 0xabcd1234 2
+
+  [vendor_id]
+  0xdeadbeef
+------------------------------------------------------------------------
+
+In the similar way, you can override the codec subsystem_id via
+`[subsystem_id]`, the revision id via `[revision_id]` line.
+Also, the codec chip name can be rewritten via `[chip_name]` line.
+------------------------------------------------------------------------
+  [codec]
+  0x12345678 0xabcd1234 2
+
+  [subsystem_id]
+  0xffff1111
+
+  [revision_id]
+  0x10
+
+  [chip_name]
+  My-own NEWS-0002
+------------------------------------------------------------------------
+
 The hd-audio driver reads the file via request_firmware().  Thus,
 a patch file has to be located on the appropriate firmware path,
 typically, /lib/firmware.  For example, when you pass the option
index 3f0c59f6d8aa07dc5b68f96d1e928ac7f5b222d5..71a243294142a41f6a80c0a4dc1e7149aa338dcf 100644 (file)
@@ -329,7 +329,7 @@ extern pgd_t swapper_pg_dir[1024];
  * tables contain all the necessary information.
  */
 extern inline void update_mmu_cache(struct vm_area_struct * vma,
-       unsigned long address, pte_t pte)
+       unsigned long address, pte_t *ptep)
 {
 }
 
index 184a6bd548250aaeb6617618fd66e1a34305d144..3b181284970f6e970b76bdd653882df90eb17b01 100644 (file)
@@ -12,6 +12,7 @@ config ARM
        select HAVE_IDE
        select RTC_LIB
        select SYS_SUPPORTS_APM_EMULATION
+       select GENERIC_ATOMIC64 if (!CPU_32v6K)
        select HAVE_OPROFILE
        select HAVE_ARCH_KGDB
        select HAVE_KPROBES if (!XIP_KERNEL)
@@ -20,6 +21,8 @@ config ARM
        select HAVE_GENERIC_DMA_COHERENT
        select HAVE_KERNEL_GZIP
        select HAVE_KERNEL_LZO
+       select HAVE_PERF_EVENTS
+       select PERF_USE_VMALLOC
        help
          The ARM series is a line of low-power-consumption RISC chip designs
          licensed by ARM Ltd and targeted at embedded applications and
@@ -52,6 +55,9 @@ config HAVE_TCM
        bool
        select GENERIC_ALLOCATOR
 
+config HAVE_PROC_CPU
+       bool
+
 config NO_IOPORT
        bool
 
@@ -161,6 +167,11 @@ config ARCH_MTD_XIP
 config GENERIC_HARDIRQS_NO__DO_IRQ
        def_bool y
 
+config ARM_L1_CACHE_SHIFT_6
+       bool
+       help
+         Setting ARM L1 cache line size to 64 Bytes.
+
 if OPROFILE
 
 config OPROFILE_ARMV6
@@ -550,10 +561,20 @@ config ARCH_W90X900
          <http://www.nuvoton.com/hq/enu/ProductAndSales/ProductLines/
                ConsumerElectronicsIC/ARMMicrocontroller/ARMMicrocontroller>
 
+config ARCH_NUC93X
+       bool "Nuvoton NUC93X CPU"
+       select CPU_ARM926T
+       select HAVE_CLK
+       select COMMON_CLKDEV
+       help
+         Support for Nuvoton (Winbond logic dept.) NUC93X MCU,The NUC93X is a
+         low-power and high performance MPEG-4/JPEG multimedia controller chip.
+
 config ARCH_PNX4008
        bool "Philips Nexperia PNX4008 Mobile"
        select CPU_ARM926T
        select HAVE_CLK
+       select COMMON_CLKDEV
        help
          This enables support for Philips PNX4008 mobile platform.
 
@@ -638,6 +659,7 @@ config ARCH_S5PC1XX
        select GENERIC_GPIO
        select HAVE_CLK
        select CPU_V7
+       select ARM_L1_CACHE_SHIFT_6
        help
          Samsung S5PC1XX series based systems
 
@@ -785,6 +807,8 @@ source "arch/arm/plat-nomadik/Kconfig"
 
 source "arch/arm/mach-ns9xxx/Kconfig"
 
+source "arch/arm/mach-nuc93x/Kconfig"
+
 source "arch/arm/plat-omap/Kconfig"
 
 source "arch/arm/mach-omap1/Kconfig"
@@ -867,6 +891,11 @@ config XSCALE_PMU
        depends on CPU_XSCALE && !XSCALE_PMU_TIMER
        default y
 
+config CPU_HAS_PMU
+       depends on CPU_V6 || CPU_V7 || XSCALE_PMU
+       default y
+       bool
+
 if !MMU
 source "arch/arm/Kconfig-nommu"
 endif
@@ -921,6 +950,19 @@ config ARM_ERRATA_460075
          ACTLR register. Note that setting specific bits in the ACTLR register
          may not be available in non-secure mode.
 
+config PL310_ERRATA_588369
+       bool "Clean & Invalidate maintenance operations do not invalidate clean lines"
+       depends on CACHE_L2X0 && ARCH_OMAP4
+       help
+          The PL310 L2 cache controller implements three types of Clean &
+          Invalidate maintenance operations: by Physical Address
+          (offset 0x7F0), by Index/Way (0x7F8) and by Way (0x7FC).
+          They are architecturally defined to behave as the execution of a
+          clean operation followed immediately by an invalidate operation,
+          both performing to the same memory location. This functionality
+          is not correctly implemented in PL310 as clean lines are not
+          invalidated as a result of these operations. Note that this errata
+          uses Texas Instrument's secure monitor api.
 endmenu
 
 source "arch/arm/common/Kconfig"
@@ -1171,6 +1213,14 @@ config HIGHPTE
        depends on HIGHMEM
        depends on !OUTER_CACHE
 
+config HW_PERF_EVENTS
+       bool "Enable hardware performance counter support for perf events"
+       depends on PERF_EVENTS && CPU_HAS_PMU && (CPU_V6 || CPU_V7)
+       default y
+       help
+         Enable hardware performance counter support for perf events. If
+         disabled, perf events will use software events only.
+
 source "mm/Kconfig"
 
 config LEDS
@@ -1230,6 +1280,7 @@ config ALIGNMENT_TRAP
        bool
        depends on CPU_CP15_MMU
        default y if !ARCH_EBSA110
+       select HAVE_PROC_CPU if PROC_FS
        help
          ARM processors cannot fetch/store information which is not
          naturally aligned on the bus, i.e., a 4 byte fetch must start at an
index 356d702c080867183f9dd9f9c16dd5826426354a..81f54ca30788b7acfdae92e00595e5fd64e46aa0 100644 (file)
@@ -171,6 +171,7 @@ machine-$(CONFIG_ARCH_U300)         := u300
 machine-$(CONFIG_ARCH_U8500)           := ux500
 machine-$(CONFIG_ARCH_VERSATILE)       := versatile
 machine-$(CONFIG_ARCH_W90X900)         := w90x900
+machine-$(CONFIG_ARCH_NUC93X)          := nuc93x
 machine-$(CONFIG_FOOTBRIDGE)           := footbridge
 
 # Platform directory name.  This list is sorted alphanumerically
index 2d4d88ba73bf9533598b074b08cce94ee85ae26c..97c89e7de7d3a64d76fb5996595f3ef1a8d9db89 100644 (file)
@@ -5,7 +5,7 @@
 #
 
 HEAD   = head.o
-OBJS   = misc.o
+OBJS   = misc.o decompress.o
 FONTC  = $(srctree)/drivers/video/console/font_acorn_8x8.c
 
 #
@@ -106,10 +106,6 @@ lib1funcs = $(obj)/lib1funcs.o
 $(obj)/lib1funcs.S: $(srctree)/arch/$(SRCARCH)/lib/lib1funcs.S FORCE
        $(call cmd,shipped)
 
-# Don't allow any static data in misc.o, which
-# would otherwise mess up our GOT table
-CFLAGS_misc.o := -Dstatic=
-
 $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \
                $(addprefix $(obj)/, $(OBJS)) $(lib1funcs) FORCE
        $(call if_changed,ld)
diff --git a/arch/arm/boot/compressed/decompress.c b/arch/arm/boot/compressed/decompress.c
new file mode 100644 (file)
index 0000000..0da382f
--- /dev/null
@@ -0,0 +1,45 @@
+#define _LINUX_STRING_H_
+
+#include <linux/compiler.h>    /* for inline */
+#include <linux/types.h>       /* for size_t */
+#include <linux/stddef.h>      /* for NULL */
+#include <linux/linkage.h>
+#include <asm/string.h>
+
+extern unsigned long free_mem_ptr;
+extern unsigned long free_mem_end_ptr;
+extern void error(char *);
+
+#define STATIC static
+
+#define ARCH_HAS_DECOMP_WDOG
+
+/* Diagnostic functions */
+#ifdef DEBUG
+#  define Assert(cond,msg) {if(!(cond)) error(msg);}
+#  define Trace(x) fprintf x
+#  define Tracev(x) {if (verbose) fprintf x ;}
+#  define Tracevv(x) {if (verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+#ifdef CONFIG_KERNEL_GZIP
+#include "../../../../lib/decompress_inflate.c"
+#endif
+
+#ifdef CONFIG_KERNEL_LZO
+#include "../../../../lib/decompress_unlzo.c"
+#endif
+
+void do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x))
+{
+       decompress(input, len, NULL, NULL, output, NULL, error);
+}
index 4fddc509e78ed3e25a8d708521f6d20cd2282e96..99b75aa1c2ec734ffa438b0aeada6d8266adb0e0 100644 (file)
 #if defined(CONFIG_DEBUG_ICEDCC)
 
 #ifdef CONFIG_CPU_V6
-               .macro  loadsp, rb
+               .macro  loadsp, rb, tmp
                .endm
                .macro  writeb, ch, rb
                mcr     p14, 0, \ch, c0, c5, 0
                .endm
 #elif defined(CONFIG_CPU_V7)
-               .macro  loadsp, rb
+               .macro  loadsp, rb, tmp
                .endm
                .macro  writeb, ch, rb
 wait:          mrc     p14, 0, pc, c0, c1, 0
@@ -36,13 +36,13 @@ wait:               mrc     p14, 0, pc, c0, c1, 0
                mcr     p14, 0, \ch, c0, c5, 0
                .endm
 #elif defined(CONFIG_CPU_XSCALE)
-               .macro  loadsp, rb
+               .macro  loadsp, rb, tmp
                .endm
                .macro  writeb, ch, rb
                mcr     p14, 0, \ch, c8, c0, 0
                .endm
 #else
-               .macro  loadsp, rb
+               .macro  loadsp, rb, tmp
                .endm
                .macro  writeb, ch, rb
                mcr     p14, 0, \ch, c1, c0, 0
@@ -58,7 +58,7 @@ wait:         mrc     p14, 0, pc, c0, c1, 0
                .endm
 
 #if defined(CONFIG_ARCH_SA1100)
-               .macro  loadsp, rb
+               .macro  loadsp, rb, tmp
                mov     \rb, #0x80000000        @ physical base address
 #ifdef CONFIG_DEBUG_LL_SER3
                add     \rb, \rb, #0x00050000   @ Ser3
@@ -67,13 +67,13 @@ wait:               mrc     p14, 0, pc, c0, c1, 0
 #endif
                .endm
 #elif defined(CONFIG_ARCH_S3C2410)
-               .macro loadsp, rb
+               .macro loadsp, rb, tmp
                mov     \rb, #0x50000000
                add     \rb, \rb, #0x4000 * CONFIG_S3C_LOWLEVEL_UART_PORT
                .endm
 #else
-               .macro  loadsp, rb
-               addruart \rb
+               .macro  loadsp, rb, tmp
+               addruart \rb, \tmp
                .endm
 #endif
 #endif
@@ -1025,7 +1025,7 @@ phex:             adr     r3, phexbuf
                strb    r2, [r3, r1]
                b       1b
 
-puts:          loadsp  r3
+puts:          loadsp  r3, r1
 1:             ldrb    r2, [r0], #1
                teq     r2, #0
                moveq   pc, lr
@@ -1042,7 +1042,7 @@ puts:             loadsp  r3
 putc:
                mov     r2, r0
                mov     r0, #0
-               loadsp  r3
+               loadsp  r3, r1
                b       2b
 
 memdump:       mov     r12, r0
index 56a0d116d27147445a4f69aa18728074f431ef9a..d32bc71c1f787d8887b2a0d1c9a6cf41730dc23c 100644 (file)
@@ -23,8 +23,8 @@ unsigned int __machine_arch_type;
 #include <linux/compiler.h>    /* for inline */
 #include <linux/types.h>       /* for size_t */
 #include <linux/stddef.h>      /* for NULL */
-#include <asm/string.h>
 #include <linux/linkage.h>
+#include <asm/string.h>
 
 #include <asm/unaligned.h>
 
@@ -117,57 +117,7 @@ static void putstr(const char *ptr)
 
 #endif
 
-#define __ptr_t void *
-
-#define memzero(s,n) __memzero(s,n)
-
-/*
- * Optimised C version of memzero for the ARM.
- */
-void __memzero (__ptr_t s, size_t n)
-{
-       union { void *vp; unsigned long *ulp; unsigned char *ucp; } u;
-       int i;
-
-       u.vp = s;
-
-       for (i = n >> 5; i > 0; i--) {
-               *u.ulp++ = 0;
-               *u.ulp++ = 0;
-               *u.ulp++ = 0;
-               *u.ulp++ = 0;
-               *u.ulp++ = 0;
-               *u.ulp++ = 0;
-               *u.ulp++ = 0;
-               *u.ulp++ = 0;
-       }
-
-       if (n & 1 << 4) {
-               *u.ulp++ = 0;
-               *u.ulp++ = 0;
-               *u.ulp++ = 0;
-               *u.ulp++ = 0;
-       }
-
-       if (n & 1 << 3) {
-               *u.ulp++ = 0;
-               *u.ulp++ = 0;
-       }
-
-       if (n & 1 << 2)
-               *u.ulp++ = 0;
-
-       if (n & 1 << 1) {
-               *u.ucp++ = 0;
-               *u.ucp++ = 0;
-       }
-
-       if (n & 1)
-               *u.ucp++ = 0;
-}
-
-static inline __ptr_t memcpy(__ptr_t __dest, __const __ptr_t __src,
-                           size_t __n)
+void *memcpy(void *__dest, __const void *__src, size_t __n)
 {
        int i = 0;
        unsigned char *d = (unsigned char *)__dest, *s = (unsigned char *)__src;
@@ -204,59 +154,20 @@ static inline __ptr_t memcpy(__ptr_t __dest, __const __ptr_t __src,
 /*
  * gzip delarations
  */
-#define STATIC static
-
-/* Diagnostic functions */
-#ifdef DEBUG
-#  define Assert(cond,msg) {if(!(cond)) error(msg);}
-#  define Trace(x) fprintf x
-#  define Tracev(x) {if (verbose) fprintf x ;}
-#  define Tracevv(x) {if (verbose>1) fprintf x ;}
-#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
-#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
-#else
-#  define Assert(cond,msg)
-#  define Trace(x)
-#  define Tracev(x)
-#  define Tracevv(x)
-#  define Tracec(c,x)
-#  define Tracecv(c,x)
-#endif
-
-static void error(char *m);
-
 extern char input_data[];
 extern char input_data_end[];
 
-static unsigned char *output_data;
-static unsigned long output_ptr;
-
-static void error(char *m);
+unsigned char *output_data;
+unsigned long output_ptr;
 
-static void putstr(const char *);
-
-static unsigned long free_mem_ptr;
-static unsigned long free_mem_end_ptr;
-
-#ifdef STANDALONE_DEBUG
-#define NO_INFLATE_MALLOC
-#endif
-
-#define ARCH_HAS_DECOMP_WDOG
-
-#ifdef CONFIG_KERNEL_GZIP
-#include "../../../../lib/decompress_inflate.c"
-#endif
-
-#ifdef CONFIG_KERNEL_LZO
-#include "../../../../lib/decompress_unlzo.c"
-#endif
+unsigned long free_mem_ptr;
+unsigned long free_mem_end_ptr;
 
 #ifndef arch_error
 #define arch_error(x)
 #endif
 
-static void error(char *x)
+void error(char *x)
 {
        arch_error(x);
 
@@ -272,6 +183,8 @@ asmlinkage void __div0(void)
        error("Attempting division by 0!");
 }
 
+extern void do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x));
+
 #ifndef STANDALONE_DEBUG
 
 unsigned long
@@ -292,8 +205,8 @@ decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p,
        output_ptr = get_unaligned_le32(tmp);
 
        putstr("Uncompressing Linux...");
-       decompress(input_data, input_data_end - input_data,
-                       NULL, NULL, output_data, NULL, error);
+       do_decompress(input_data, input_data_end - input_data,
+                       output_data, error);
        putstr(" done, booting the kernel.\n");
        return output_ptr;
 }
index a5924b9b88bdbad7a2daea6489faf712152174b8..7ca9ecff652ff346bbdfec69bc03fb3752ef9a8c 100644 (file)
@@ -14,6 +14,13 @@ SECTIONS
   /DISCARD/ : {
     *(.ARM.exidx*)
     *(.ARM.extab*)
+    /*
+     * Discard any r/w data - this produces a link error if we have any,
+     * which is required for PIC decompression.  Local data generates
+     * GOTOFF relocations, which prevents it being relocated independently
+     * of the text/got segments.
+     */
+    *(.data)
   }
 
   . = TEXT_START;
@@ -40,7 +47,6 @@ SECTIONS
   .got                 : { *(.got) }
   _got_end = .;
   .got.plt             : { *(.got.plt) }
-  .data                        : { *(.data) }
   _edata = .;
 
   . = BSS_START;
index aae5bc01acc80d20d1f4cfe46c048d78455a67cb..446b696196e363858e66d12983b2bca21126d22d 100644 (file)
@@ -99,6 +99,16 @@ void clkdev_add(struct clk_lookup *cl)
 }
 EXPORT_SYMBOL(clkdev_add);
 
+void __init clkdev_add_table(struct clk_lookup *cl, size_t num)
+{
+       mutex_lock(&clocks_mutex);
+       while (num--) {
+               list_add_tail(&cl->node, &clocks);
+               cl++;
+       }
+       mutex_unlock(&clocks_mutex);
+}
+
 #define MAX_DEV_ID     20
 #define MAX_CON_ID     16
 
index cc32c1e54a59825dc93fcbba098fcdbd51d9c8f0..cc0a932bbea90780f659becc4ee7d93087ab61cf 100644 (file)
@@ -277,7 +277,7 @@ static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size,
                 * We don't need to sync the DMA buffer since
                 * it was allocated via the coherent allocators.
                 */
-               dma_cache_maint(ptr, size, dir);
+               __dma_single_cpu_to_dev(ptr, size, dir);
        }
 
        return dma_addr;
@@ -315,6 +315,8 @@ static inline void unmap_single(struct device *dev, dma_addr_t dma_addr,
                        __cpuc_flush_dcache_area(ptr, size);
                }
                free_safe_buffer(dev->archdata.dmabounce, buf);
+       } else {
+               __dma_single_dev_to_cpu(dma_to_virt(dev, dma_addr), size, dir);
        }
 }
 
index f232941de8abc4c56e9074d3f83ebbe672907be3..1cf999ade4bc181855379a10d724eac917b83da7 100644 (file)
@@ -18,6 +18,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
+
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/io.h>
 #include <asm/mach/irq.h>
 #include <asm/hardware/vic.h>
 
-static void vic_ack_irq(unsigned int irq)
-{
-       void __iomem *base = get_irq_chip_data(irq);
-       irq &= 31;
-       writel(1 << irq, base + VIC_INT_ENABLE_CLEAR);
-       /* moreover, clear the soft-triggered, in case it was the reason */
-       writel(1 << irq, base + VIC_INT_SOFT_CLEAR);
-}
-
-static void vic_mask_irq(unsigned int irq)
-{
-       void __iomem *base = get_irq_chip_data(irq);
-       irq &= 31;
-       writel(1 << irq, base + VIC_INT_ENABLE_CLEAR);
-}
-
-static void vic_unmask_irq(unsigned int irq)
-{
-       void __iomem *base = get_irq_chip_data(irq);
-       irq &= 31;
-       writel(1 << irq, base + VIC_INT_ENABLE);
-}
-
-/**
- * vic_init2 - common initialisation code
- * @base: Base of the VIC.
- *
- * Common initialisation code for registeration
- * and resume.
-*/
-static void vic_init2(void __iomem *base)
-{
-       int i;
-
-       for (i = 0; i < 16; i++) {
-               void __iomem *reg = base + VIC_VECT_CNTL0 + (i * 4);
-               writel(VIC_VECT_CNTL_ENABLE | i, reg);
-       }
-
-       writel(32, base + VIC_PL190_DEF_VECT_ADDR);
-}
-
 #if defined(CONFIG_PM)
 /**
  * struct vic_device - VIC PM device
@@ -99,13 +58,34 @@ struct vic_device {
 /* we cannot allocate memory when VICs are initially registered */
 static struct vic_device vic_devices[CONFIG_ARM_VIC_NR];
 
+static int vic_id;
+
 static inline struct vic_device *to_vic(struct sys_device *sys)
 {
        return container_of(sys, struct vic_device, sysdev);
 }
+#endif /* CONFIG_PM */
 
-static int vic_id;
+/**
+ * vic_init2 - common initialisation code
+ * @base: Base of the VIC.
+ *
+ * Common initialisation code for registeration
+ * and resume.
+*/
+static void vic_init2(void __iomem *base)
+{
+       int i;
+
+       for (i = 0; i < 16; i++) {
+               void __iomem *reg = base + VIC_VECT_CNTL0 + (i * 4);
+               writel(VIC_VECT_CNTL_ENABLE | i, reg);
+       }
+
+       writel(32, base + VIC_PL190_DEF_VECT_ADDR);
+}
 
+#if defined(CONFIG_PM)
 static int vic_class_resume(struct sys_device *dev)
 {
        struct vic_device *vic = to_vic(dev);
@@ -158,31 +138,6 @@ struct sysdev_class vic_class = {
        .resume         = vic_class_resume,
 };
 
-/**
- * vic_pm_register - Register a VIC for later power management control
- * @base: The base address of the VIC.
- * @irq: The base IRQ for the VIC.
- * @resume_sources: bitmask of interrupts allowed for resume sources.
- *
- * Register the VIC with the system device tree so that it can be notified
- * of suspend and resume requests and ensure that the correct actions are
- * taken to re-instate the settings on resume.
- */
-static void __init vic_pm_register(void __iomem *base, unsigned int irq, u32 resume_sources)
-{
-       struct vic_device *v;
-
-       if (vic_id >= ARRAY_SIZE(vic_devices))
-               printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__);
-       else {
-               v = &vic_devices[vic_id];
-               v->base = base;
-               v->resume_sources = resume_sources;
-               v->irq = irq;
-               vic_id++;
-       }
-}
-
 /**
  * vic_pm_init - initicall to register VIC pm
  *
@@ -219,9 +174,60 @@ static int __init vic_pm_init(void)
 
        return 0;
 }
-
 late_initcall(vic_pm_init);
 
+/**
+ * vic_pm_register - Register a VIC for later power management control
+ * @base: The base address of the VIC.
+ * @irq: The base IRQ for the VIC.
+ * @resume_sources: bitmask of interrupts allowed for resume sources.
+ *
+ * Register the VIC with the system device tree so that it can be notified
+ * of suspend and resume requests and ensure that the correct actions are
+ * taken to re-instate the settings on resume.
+ */
+static void __init vic_pm_register(void __iomem *base, unsigned int irq, u32 resume_sources)
+{
+       struct vic_device *v;
+
+       if (vic_id >= ARRAY_SIZE(vic_devices))
+               printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__);
+       else {
+               v = &vic_devices[vic_id];
+               v->base = base;
+               v->resume_sources = resume_sources;
+               v->irq = irq;
+               vic_id++;
+       }
+}
+#else
+static inline void vic_pm_register(void __iomem *base, unsigned int irq, u32 arg1) { }
+#endif /* CONFIG_PM */
+
+static void vic_ack_irq(unsigned int irq)
+{
+       void __iomem *base = get_irq_chip_data(irq);
+       irq &= 31;
+       writel(1 << irq, base + VIC_INT_ENABLE_CLEAR);
+       /* moreover, clear the soft-triggered, in case it was the reason */
+       writel(1 << irq, base + VIC_INT_SOFT_CLEAR);
+}
+
+static void vic_mask_irq(unsigned int irq)
+{
+       void __iomem *base = get_irq_chip_data(irq);
+       irq &= 31;
+       writel(1 << irq, base + VIC_INT_ENABLE_CLEAR);
+}
+
+static void vic_unmask_irq(unsigned int irq)
+{
+       void __iomem *base = get_irq_chip_data(irq);
+       irq &= 31;
+       writel(1 << irq, base + VIC_INT_ENABLE);
+}
+
+#if defined(CONFIG_PM)
 static struct vic_device *vic_from_irq(unsigned int irq)
 {
         struct vic_device *v = vic_devices;
@@ -255,10 +261,7 @@ static int vic_set_wake(unsigned int irq, unsigned int on)
 
        return 0;
 }
-
 #else
-static inline void vic_pm_register(void __iomem *base, unsigned int irq, u32 arg1) { }
-
 #define vic_set_wake NULL
 #endif /* CONFIG_PM */
 
@@ -270,9 +273,62 @@ static struct irq_chip vic_chip = {
        .set_wake = vic_set_wake,
 };
 
-/* The PL190 cell from ARM has been modified by ST, so handle both here */
-static void vik_init_st(void __iomem *base, unsigned int irq_start,
-                        u32 vic_sources);
+/*
+ * The PL190 cell from ARM has been modified by ST to handle 64 interrupts.
+ * The original cell has 32 interrupts, while the modified one has 64,
+ * replocating two blocks 0x00..0x1f in 0x20..0x3f. In that case
+ * the probe function is called twice, with base set to offset 000
+ *  and 020 within the page. We call this "second block".
+ */
+static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
+                               u32 vic_sources)
+{
+       unsigned int i;
+       int vic_2nd_block = ((unsigned long)base & ~PAGE_MASK) != 0;
+
+       /* Disable all interrupts initially. */
+
+       writel(0, base + VIC_INT_SELECT);
+       writel(0, base + VIC_INT_ENABLE);
+       writel(~0, base + VIC_INT_ENABLE_CLEAR);
+       writel(0, base + VIC_IRQ_STATUS);
+       writel(0, base + VIC_ITCR);
+       writel(~0, base + VIC_INT_SOFT_CLEAR);
+
+       /*
+        * Make sure we clear all existing interrupts. The vector registers
+        * in this cell are after the second block of general registers,
+        * so we can address them using standard offsets, but only from
+        * the second base address, which is 0x20 in the page
+        */
+       if (vic_2nd_block) {
+               writel(0, base + VIC_PL190_VECT_ADDR);
+               for (i = 0; i < 19; i++) {
+                       unsigned int value;
+
+                       value = readl(base + VIC_PL190_VECT_ADDR);
+                       writel(value, base + VIC_PL190_VECT_ADDR);
+               }
+               /* ST has 16 vectors as well, but we don't enable them by now */
+               for (i = 0; i < 16; i++) {
+                       void __iomem *reg = base + VIC_VECT_CNTL0 + (i * 4);
+                       writel(0, reg);
+               }
+
+               writel(32, base + VIC_PL190_DEF_VECT_ADDR);
+       }
+
+       for (i = 0; i < 32; i++) {
+               if (vic_sources & (1 << i)) {
+                       unsigned int irq = irq_start + i;
+
+                       set_irq_chip(irq, &vic_chip);
+                       set_irq_chip_data(irq, base);
+                       set_irq_handler(irq, handle_level_irq);
+                       set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+               }
+       }
+}
 
 /**
  * vic_init - initialise a vectored interrupt controller
@@ -299,7 +355,7 @@ void __init vic_init(void __iomem *base, unsigned int irq_start,
 
        switch(vendor) {
        case AMBA_VENDOR_ST:
-               vik_init_st(base, irq_start, vic_sources);
+               vic_init_st(base, irq_start, vic_sources);
                return;
        default:
                printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");
@@ -343,60 +399,3 @@ void __init vic_init(void __iomem *base, unsigned int irq_start,
 
        vic_pm_register(base, irq_start, resume_sources);
 }
-
-/*
- * The PL190 cell from ARM has been modified by ST to handle 64 interrupts.
- * The original cell has 32 interrupts, while the modified one has 64,
- * replocating two blocks 0x00..0x1f in 0x20..0x3f. In that case
- * the probe function is called twice, with base set to offset 000
- *  and 020 within the page. We call this "second block".
- */
-static void __init vik_init_st(void __iomem *base, unsigned int irq_start,
-                               u32 vic_sources)
-{
-       unsigned int i;
-       int vic_2nd_block = ((unsigned long)base & ~PAGE_MASK) != 0;
-
-       /* Disable all interrupts initially. */
-
-       writel(0, base + VIC_INT_SELECT);
-       writel(0, base + VIC_INT_ENABLE);
-       writel(~0, base + VIC_INT_ENABLE_CLEAR);
-       writel(0, base + VIC_IRQ_STATUS);
-       writel(0, base + VIC_ITCR);
-       writel(~0, base + VIC_INT_SOFT_CLEAR);
-
-       /*
-        * Make sure we clear all existing interrupts. The vector registers
-        * in this cell are after the second block of general registers,
-        * so we can address them using standard offsets, but only from
-        * the second base address, which is 0x20 in the page
-        */
-       if (vic_2nd_block) {
-               writel(0, base + VIC_PL190_VECT_ADDR);
-               for (i = 0; i < 19; i++) {
-                       unsigned int value;
-
-                       value = readl(base + VIC_PL190_VECT_ADDR);
-                       writel(value, base + VIC_PL190_VECT_ADDR);
-               }
-               /* ST has 16 vectors as well, but we don't enable them by now */
-               for (i = 0; i < 16; i++) {
-                       void __iomem *reg = base + VIC_VECT_CNTL0 + (i * 4);
-                       writel(0, reg);
-               }
-
-               writel(32, base + VIC_PL190_DEF_VECT_ADDR);
-       }
-
-       for (i = 0; i < 32; i++) {
-               if (vic_sources & (1 << i)) {
-                       unsigned int irq = irq_start + i;
-
-                       set_irq_chip(irq, &vic_chip);
-                       set_irq_chip_data(irq, base);
-                       set_irq_handler(irq, handle_level_irq);
-                       set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
-               }
-       }
-}
diff --git a/arch/arm/configs/at572d940hfek_defconfig b/arch/arm/configs/at572d940hfek_defconfig
new file mode 100644 (file)
index 0000000..76d724b
--- /dev/null
@@ -0,0 +1,1640 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.28-rc7
+# Fri Dec  5 10:58:47 2008
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION="-AT572D940HF"
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_TASKSTATS=y
+# CONFIG_TASK_DELAY_ACCT is not set
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_AUDIT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_CGROUPS=y
+# CONFIG_CGROUP_DEBUG is not set
+# CONFIG_CGROUP_NS is not set
+# CONFIG_CGROUP_FREEZER is not set
+# CONFIG_CGROUP_DEVICE is not set
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+# CONFIG_USER_SCHED is not set
+CONFIG_CGROUP_SCHED=y
+CONFIG_CGROUP_CPUACCT=y
+# CONFIG_RESOURCE_COUNTERS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_RELAY=y
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+CONFIG_MARKERS=y
+CONFIG_OPROFILE=m
+CONFIG_HAVE_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_KRETPROBES=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+CONFIG_BLK_DEV_IO_TRACE=y
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_CLASSIC_RCU=y
+# CONFIG_FREEZER is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+CONFIG_ARCH_AT91=y
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_MSM is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Atmel AT91 System-on-Chip
+#
+# CONFIG_ARCH_AT91RM9200 is not set
+# CONFIG_ARCH_AT91SAM9260 is not set
+# CONFIG_ARCH_AT91SAM9261 is not set
+# CONFIG_ARCH_AT91SAM9263 is not set
+# CONFIG_ARCH_AT91SAM9RL is not set
+# CONFIG_ARCH_AT91SAM9G20 is not set
+# CONFIG_ARCH_AT91CAP9 is not set
+# CONFIG_ARCH_AT91X40 is not set
+CONFIG_ARCH_AT572D940HF=y
+CONFIG_AT91_PMC_UNIT=y
+
+#
+# AT572D940HF Board Type
+#
+CONFIG_MACH_AT572D940HFEB=y
+
+#
+# AT91 Board Options
+#
+# CONFIG_MTD_AT91_DATAFLASH_CARD is not set
+# CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16 is not set
+CONFIG_NUM_SERIAL=3
+
+#
+# AT91 Feature Selections
+#
+CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
+CONFIG_AT91_TIMER_HZ=100
+CONFIG_AT91_EARLY_DBGU=y
+# CONFIG_AT91_EARLY_USART0 is not set
+# CONFIG_AT91_EARLY_USART1 is not set
+# CONFIG_AT91_EARLY_USART2 is not set
+# CONFIG_AT91_EARLY_USART3 is not set
+# CONFIG_AT91_EARLY_USART4 is not set
+# CONFIG_AT91_EARLY_USART5 is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+CONFIG_RESOURCES_64BIT=y
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_CMDLINE="mem=48M console=ttyS0 initrd=0x21100000,3145728 root=/dev/ram0 rw ip=172.16.1.181"
+# CONFIG_XIP_KERNEL is not set
+CONFIG_KEXEC=y
+CONFIG_ATAGS_PROC=y
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+CONFIG_FPE_NWFPE_XP=y
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=m
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+CONFIG_NET_PKTGEN=m
+CONFIG_NET_TCPPROBE=m
+# CONFIG_HAMRADIO is not set
+CONFIG_CAN=m
+CONFIG_CAN_RAW=m
+CONFIG_CAN_BCM=m
+
+#
+# CAN Device Drivers
+#
+CONFIG_CAN_VCAN=m
+CONFIG_CAN_DEBUG_DEVICES=y
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_PHONET is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+CONFIG_WIRELESS_OLD_REGULATORY=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+# CONFIG_MAC80211 is not set
+CONFIG_IEEE80211=m
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=m
+# CONFIG_IEEE80211_CRYPT_CCMP is not set
+# CONFIG_IEEE80211_CRYPT_TKIP is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_CONNECTOR=m
+CONFIG_MTD=m
+CONFIG_MTD_DEBUG=y
+CONFIG_MTD_DEBUG_VERBOSE=1
+CONFIG_MTD_CONCAT=m
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLKDEVS=m
+CONFIG_MTD_BLOCK=m
+CONFIG_MTD_BLOCK_RO=m
+CONFIG_FTL=m
+CONFIG_NFTL=m
+CONFIG_NFTL_RW=y
+CONFIG_INFTL=m
+CONFIG_RFD_FTL=m
+CONFIG_SSFDC=m
+CONFIG_MTD_OOPS=m
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=m
+CONFIG_MTD_JEDECPROBE=m
+CONFIG_MTD_GEN_PROBE=m
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=m
+CONFIG_MTD_CFI_AMDSTD=m
+CONFIG_MTD_CFI_STAA=m
+CONFIG_MTD_CFI_UTIL=m
+CONFIG_MTD_RAM=m
+CONFIG_MTD_ROM=m
+CONFIG_MTD_ABSENT=m
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_PHYSMAP=m
+CONFIG_MTD_PHYSMAP_START=0x8000000
+CONFIG_MTD_PHYSMAP_LEN=0x4000000
+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_IMPA7 is not set
+CONFIG_MTD_PLATRAM=m
+
+#
+# Self-contained MTD device drivers
+#
+CONFIG_MTD_DATAFLASH=m
+# CONFIG_MTD_DATAFLASH_WRITE_VERIFY is not set
+# CONFIG_MTD_DATAFLASH_OTP is not set
+CONFIG_MTD_M25P80=m
+CONFIG_M25PXX_USE_FAST_READ=y
+CONFIG_MTD_SLRAM=m
+CONFIG_MTD_PHRAM=m
+CONFIG_MTD_MTDRAM=m
+CONFIG_MTDRAM_TOTAL_SIZE=4096
+CONFIG_MTDRAM_ERASE_SIZE=128
+CONFIG_MTD_BLOCK2MTD=m
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=m
+CONFIG_MTD_NAND_VERIFY_WRITE=y
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_GPIO is not set
+CONFIG_MTD_NAND_IDS=m
+CONFIG_MTD_NAND_DISKONCHIP=m
+# CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED is not set
+CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0
+# CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE is not set
+# CONFIG_MTD_NAND_ATMEL is not set
+CONFIG_MTD_NAND_NANDSIM=m
+CONFIG_MTD_NAND_PLATFORM=m
+CONFIG_MTD_ALAUDA=m
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+CONFIG_MTD_UBI=m
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_RESERVE=1
+CONFIG_MTD_UBI_GLUEBI=y
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=65536
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+CONFIG_ATMEL_TCLIB=y
+CONFIG_ATMEL_TCB_CLKSRC=y
+CONFIG_ATMEL_TCB_CLKSRC_BLOCK=0
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_ICS932S401 is not set
+CONFIG_ATMEL_SSC=m
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_C2PORT is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_RAID_ATTRS=m
+CONFIG_SCSI=m
+CONFIG_SCSI_DMA=y
+CONFIG_SCSI_TGT=m
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=m
+CONFIG_CHR_DEV_SCH=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+CONFIG_SCSI_ISCSI_ATTRS=m
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+CONFIG_MACVLAN=m
+CONFIG_EQUALIZER=m
+CONFIG_TUN=m
+CONFIG_VETH=m
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+CONFIG_MARVELL_PHY=m
+CONFIG_DAVICOM_PHY=m
+CONFIG_QSEMI_PHY=m
+CONFIG_LXT_PHY=m
+CONFIG_CICADA_PHY=m
+CONFIG_VITESSE_PHY=m
+CONFIG_SMSC_PHY=m
+CONFIG_BROADCOM_PHY=m
+CONFIG_ICPLUS_PHY=m
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_FIXED_PHY is not set
+CONFIG_MDIO_BITBANG=m
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=m
+CONFIG_MACB=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_SMC911X is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+CONFIG_WLAN_PRE80211=y
+CONFIG_STRIP=m
+CONFIG_WLAN_80211=y
+CONFIG_LIBERTAS=m
+CONFIG_LIBERTAS_USB=m
+CONFIG_LIBERTAS_SDIO=m
+# CONFIG_LIBERTAS_DEBUG is not set
+CONFIG_USB_ZD1201=m
+# CONFIG_USB_NET_RNDIS_WLAN is not set
+# CONFIG_IWLWIFI_LEDS is not set
+CONFIG_HOSTAP=m
+CONFIG_HOSTAP_FIRMWARE=y
+CONFIG_HOSTAP_FIRMWARE_NVRAM=y
+
+#
+# USB Network Adapters
+#
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_USBNET=m
+CONFIG_USB_NET_AX8817X=m
+CONFIG_USB_NET_CDCETHER=m
+CONFIG_USB_NET_DM9601=m
+# CONFIG_USB_NET_SMSC95XX is not set
+CONFIG_USB_NET_GL620A=m
+CONFIG_USB_NET_NET1080=m
+CONFIG_USB_NET_PLUSB=m
+CONFIG_USB_NET_MCS7830=m
+CONFIG_USB_NET_RNDIS_HOST=m
+CONFIG_USB_NET_CDC_SUBSET=m
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_KC2190=y
+# CONFIG_USB_NET_ZAURUS is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+CONFIG_INPUT_POLLDEV=m
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=m
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=m
+CONFIG_INPUT_EVBUG=m
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+CONFIG_KEYBOARD_SUNKBD=m
+CONFIG_KEYBOARD_LKKBD=m
+CONFIG_KEYBOARD_XTKBD=m
+CONFIG_KEYBOARD_NEWTON=m
+CONFIG_KEYBOARD_STOWAWAY=m
+CONFIG_KEYBOARD_GPIO=m
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=m
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_LIFEBOOK=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_ELANTECH is not set
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+CONFIG_MOUSE_SERIAL=m
+CONFIG_MOUSE_APPLETOUCH=m
+# CONFIG_MOUSE_BCM5974 is not set
+CONFIG_MOUSE_VSXXXAA=m
+CONFIG_MOUSE_GPIO=m
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_CM109 is not set
+CONFIG_INPUT_UINPUT=m
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_LIBPS2=y
+CONFIG_SERIO_RAW=m
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_DEVKMEM=y
+CONFIG_SERIAL_NONSTANDARD=y
+CONFIG_N_HDLC=m
+# CONFIG_RISCOM8 is not set
+CONFIG_SPECIALIX=m
+CONFIG_RIO=m
+# CONFIG_RIO_OLDPCI is not set
+CONFIG_STALDRV=y
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+CONFIG_SERIAL_ATMEL_PDC=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+CONFIG_IPMI_HANDLER=m
+# CONFIG_IPMI_PANIC_EVENT is not set
+CONFIG_IPMI_DEVICE_INTERFACE=m
+CONFIG_IPMI_SI=m
+CONFIG_IPMI_WATCHDOG=m
+CONFIG_IPMI_POWEROFF=m
+CONFIG_HW_RANDOM=y
+CONFIG_NVRAM=m
+CONFIG_R3964=m
+CONFIG_RAW_DRIVER=m
+CONFIG_MAX_RAW_DEVS=256
+CONFIG_TCG_TPM=m
+CONFIG_TCG_NSC=m
+CONFIG_TCG_ATMEL=m
+CONFIG_I2C=m
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+CONFIG_DS1682=m
+# CONFIG_AT24 is not set
+CONFIG_SENSORS_EEPROM=m
+CONFIG_SENSORS_PCF8574=m
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+CONFIG_SENSORS_PCF8591=m
+CONFIG_SENSORS_MAX6875=m
+CONFIG_SENSORS_TSL2550=m
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_ATMEL=y
+CONFIG_SPI_BITBANG=m
+
+#
+# SPI Protocol Masters
+#
+CONFIG_SPI_AT25=m
+CONFIG_SPI_SPIDEV=m
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_SOUND=m
+CONFIG_SOUND_OSS_CORE=y
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_RAWMIDI=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+# CONFIG_SND_PCM_OSS_PLUGINS is not set
+CONFIG_SND_SEQUENCER_OSS=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_SUPPORT_OLD_API=y
+# CONFIG_SND_VERBOSE_PROCFS is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_DRIVERS=y
+CONFIG_SND_DUMMY=m
+CONFIG_SND_VIRMIDI=m
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+CONFIG_SND_ARM=y
+CONFIG_SND_SPI=y
+# CONFIG_SND_AT73C213 is not set
+CONFIG_SND_USB=y
+CONFIG_SND_USB_AUDIO=m
+CONFIG_SND_USB_CAIAQ=m
+CONFIG_SND_USB_CAIAQ_INPUT=y
+# CONFIG_SND_SOC is not set
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=m
+# CONFIG_HID_DEBUG is not set
+CONFIG_HIDRAW=y
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=m
+# CONFIG_HID_PID is not set
+CONFIG_USB_HIDDEV=y
+
+#
+# USB HID Boot Protocol drivers
+#
+CONFIG_USB_KBD=m
+CONFIG_USB_MOUSE=m
+
+#
+# Special HID drivers
+#
+CONFIG_HID_COMPAT=y
+CONFIG_HID_A4TECH=m
+CONFIG_HID_APPLE=m
+CONFIG_HID_BELKIN=m
+CONFIG_HID_BRIGHT=m
+CONFIG_HID_CHERRY=m
+CONFIG_HID_CHICONY=m
+CONFIG_HID_CYPRESS=m
+CONFIG_HID_DELL=m
+CONFIG_HID_EZKEY=m
+CONFIG_HID_GYRATION=m
+CONFIG_HID_LOGITECH=m
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+CONFIG_HID_MICROSOFT=m
+CONFIG_HID_MONTEREY=m
+CONFIG_HID_PANTHERLORD=m
+# CONFIG_PANTHERLORD_FF is not set
+CONFIG_HID_PETALYNX=m
+CONFIG_HID_SAMSUNG=m
+CONFIG_HID_SONY=m
+CONFIG_HID_SUNPLUS=m
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_ZEROPLUS_FF is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_DYNAMIC_MINORS=y
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
+#
+
+#
+# see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_DPCM=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+CONFIG_USB_STORAGE_KARMA=y
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+CONFIG_USB_LIBUSUAL=y
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+CONFIG_USB_SERIAL=m
+CONFIG_USB_EZUSB=y
+CONFIG_USB_SERIAL_GENERIC=y
+# CONFIG_USB_SERIAL_AIRCABLE is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_CH341 is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_CP2101 is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_FUNSOFT is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_IUU is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_MOS7720 is not set
+# CONFIG_USB_SERIAL_MOS7840 is not set
+# CONFIG_USB_SERIAL_MOTOROLA is not set
+# CONFIG_USB_SERIAL_NAVMAN is not set
+CONFIG_USB_SERIAL_PL2303=m
+# CONFIG_USB_SERIAL_OTI6858 is not set
+CONFIG_USB_SERIAL_SPCP8X5=m
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OPTION is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+CONFIG_USB_SERIAL_DEBUG=m
+
+#
+# USB Miscellaneous drivers
+#
+CONFIG_USB_EMI62=m
+CONFIG_USB_EMI26=m
+CONFIG_USB_ADUTUX=m
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+CONFIG_USB_TEST=m
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+CONFIG_USB_GADGET=m
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_DEBUG_FS=y
+CONFIG_USB_GADGET_VBUS_DRAW=2
+CONFIG_USB_GADGET_SELECTED=y
+CONFIG_USB_GADGET_AT91=y
+CONFIG_USB_AT91=m
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_PXA25X is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_QE is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+CONFIG_USB_ZERO=m
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
+CONFIG_USB_MIDI_GADGET=m
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+CONFIG_SDIO_UART=m
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+CONFIG_MMC_AT91=y
+CONFIG_MMC_SPI=m
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=m
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_PCA9532 is not set
+CONFIG_LEDS_GPIO=m
+# CONFIG_LEDS_PCA955X is not set
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=m
+CONFIG_LEDS_TRIGGER_HEARTBEAT=m
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+CONFIG_RTC_INTF_DEV_UIE_EMUL=y
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+CONFIG_RTC_DRV_DS1307=m
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+CONFIG_RTC_DRV_DS1305=y
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_AT91SAM9 is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+CONFIG_JBD_DEBUG=y
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+CONFIG_REISERFS_CHECK=y
+CONFIG_REISERFS_PROC_INFO=y
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=m
+CONFIG_GENERIC_ACL=y
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_CONFIGFS_FS=m
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_LZO=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_CMODE_NONE is not set
+# CONFIG_JFFS2_CMODE_PRIORITY is not set
+# CONFIG_JFFS2_CMODE_SIZE is not set
+CONFIG_JFFS2_CMODE_FAVOURLZO=y
+# CONFIG_UBIFS_FS is not set
+CONFIG_CRAMFS=m
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V2_ACL=y
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_NFS_ACL_SUPPORT=m
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+CONFIG_SUNRPC_GSS=m
+# CONFIG_SUNRPC_REGISTER_V4 is not set
+CONFIG_RPCSEC_GSS_KRB5=m
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+CONFIG_CIFS_WEAK_PW_HASH=y
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+CONFIG_LDM_PARTITION=y
+CONFIG_LDM_DEBUG=y
+CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+CONFIG_SUN_PARTITION=y
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="cp437"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=m
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+CONFIG_DLM=m
+# CONFIG_DLM_DEBUG is not set
+
+#
+# Kernel hacking
+#
+CONFIG_PRINTK_TIME=y
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+
+#
+# Tracers
+#
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_DEBUG_USER is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+CONFIG_SECURITYFS=y
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_AEAD=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_RNG=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_GF128MUL=m
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=m
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+CONFIG_CRYPTO_SHA1=m
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=m
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=m
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=m
+# CONFIG_CRC_T10DIF is not set
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC32=y
+CONFIG_CRC7=m
+CONFIG_LIBCRC32C=m
+CONFIG_AUDIT_GENERIC=y
+CONFIG_ZLIB_INFLATE=m
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_LZO_COMPRESS=m
+CONFIG_LZO_DECOMPRESS=m
+CONFIG_REED_SOLOMON=m
+CONFIG_REED_SOLOMON_DEC16=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
index 3de640ac294b300cb874ef80e8b9f31a0bd3c4a3..c48d7b893869677bc4474e3fa2d70f256a6f2adb 100644 (file)
@@ -242,10 +242,13 @@ CONFIG_CPU_CP15_MMU=y
 # CONFIG_CPU_DCACHE_DISABLE is not set
 # CONFIG_CPU_BPREDICT_DISABLE is not set
 CONFIG_HAS_TLS_REG=y
+CONFIG_OUTER_CACHE=y
+CONFIG_CACHE_L2X0=y
 CONFIG_ARM_L1_CACHE_SHIFT=5
 # CONFIG_ARM_ERRATA_430973 is not set
 # CONFIG_ARM_ERRATA_458693 is not set
 # CONFIG_ARM_ERRATA_460075 is not set
+CONFIG_PL310_ERRATA_588369=y
 CONFIG_ARM_GIC=y
 
 #
index d0daeab2234e34cc4ac8b466a037a176e188e5b7..e8ddec2cb158763d5d0a7741d44ee9e25d90696d 100644 (file)
@@ -235,6 +235,234 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
 #define smp_mb__before_atomic_inc()    smp_mb()
 #define smp_mb__after_atomic_inc()     smp_mb()
 
+#ifndef CONFIG_GENERIC_ATOMIC64
+typedef struct {
+       u64 __aligned(8) counter;
+} atomic64_t;
+
+#define ATOMIC64_INIT(i) { (i) }
+
+static inline u64 atomic64_read(atomic64_t *v)
+{
+       u64 result;
+
+       __asm__ __volatile__("@ atomic64_read\n"
+"      ldrexd  %0, %H0, [%1]"
+       : "=&r" (result)
+       : "r" (&v->counter)
+       );
+
+       return result;
+}
+
+static inline void atomic64_set(atomic64_t *v, u64 i)
+{
+       u64 tmp;
+
+       __asm__ __volatile__("@ atomic64_set\n"
+"1:    ldrexd  %0, %H0, [%1]\n"
+"      strexd  %0, %2, %H2, [%1]\n"
+"      teq     %0, #0\n"
+"      bne     1b"
+       : "=&r" (tmp)
+       : "r" (&v->counter), "r" (i)
+       : "cc");
+}
+
+static inline void atomic64_add(u64 i, atomic64_t *v)
+{
+       u64 result;
+       unsigned long tmp;
+
+       __asm__ __volatile__("@ atomic64_add\n"
+"1:    ldrexd  %0, %H0, [%2]\n"
+"      adds    %0, %0, %3\n"
+"      adc     %H0, %H0, %H3\n"
+"      strexd  %1, %0, %H0, [%2]\n"
+"      teq     %1, #0\n"
+"      bne     1b"
+       : "=&r" (result), "=&r" (tmp)
+       : "r" (&v->counter), "r" (i)
+       : "cc");
+}
+
+static inline u64 atomic64_add_return(u64 i, atomic64_t *v)
+{
+       u64 result;
+       unsigned long tmp;
+
+       smp_mb();
+
+       __asm__ __volatile__("@ atomic64_add_return\n"
+"1:    ldrexd  %0, %H0, [%2]\n"
+"      adds    %0, %0, %3\n"
+"      adc     %H0, %H0, %H3\n"
+"      strexd  %1, %0, %H0, [%2]\n"
+"      teq     %1, #0\n"
+"      bne     1b"
+       : "=&r" (result), "=&r" (tmp)
+       : "r" (&v->counter), "r" (i)
+       : "cc");
+
+       smp_mb();
+
+       return result;
+}
+
+static inline void atomic64_sub(u64 i, atomic64_t *v)
+{
+       u64 result;
+       unsigned long tmp;
+
+       __asm__ __volatile__("@ atomic64_sub\n"
+"1:    ldrexd  %0, %H0, [%2]\n"
+"      subs    %0, %0, %3\n"
+"      sbc     %H0, %H0, %H3\n"
+"      strexd  %1, %0, %H0, [%2]\n"
+"      teq     %1, #0\n"
+"      bne     1b"
+       : "=&r" (result), "=&r" (tmp)
+       : "r" (&v->counter), "r" (i)
+       : "cc");
+}
+
+static inline u64 atomic64_sub_return(u64 i, atomic64_t *v)
+{
+       u64 result;
+       unsigned long tmp;
+
+       smp_mb();
+
+       __asm__ __volatile__("@ atomic64_sub_return\n"
+"1:    ldrexd  %0, %H0, [%2]\n"
+"      subs    %0, %0, %3\n"
+"      sbc     %H0, %H0, %H3\n"
+"      strexd  %1, %0, %H0, [%2]\n"
+"      teq     %1, #0\n"
+"      bne     1b"
+       : "=&r" (result), "=&r" (tmp)
+       : "r" (&v->counter), "r" (i)
+       : "cc");
+
+       smp_mb();
+
+       return result;
+}
+
+static inline u64 atomic64_cmpxchg(atomic64_t *ptr, u64 old, u64 new)
+{
+       u64 oldval;
+       unsigned long res;
+
+       smp_mb();
+
+       do {
+               __asm__ __volatile__("@ atomic64_cmpxchg\n"
+               "ldrexd         %1, %H1, [%2]\n"
+               "mov            %0, #0\n"
+               "teq            %1, %3\n"
+               "teqeq          %H1, %H3\n"
+               "strexdeq       %0, %4, %H4, [%2]"
+               : "=&r" (res), "=&r" (oldval)
+               : "r" (&ptr->counter), "r" (old), "r" (new)
+               : "cc");
+       } while (res);
+
+       smp_mb();
+
+       return oldval;
+}
+
+static inline u64 atomic64_xchg(atomic64_t *ptr, u64 new)
+{
+       u64 result;
+       unsigned long tmp;
+
+       smp_mb();
+
+       __asm__ __volatile__("@ atomic64_xchg\n"
+"1:    ldrexd  %0, %H0, [%2]\n"
+"      strexd  %1, %3, %H3, [%2]\n"
+"      teq     %1, #0\n"
+"      bne     1b"
+       : "=&r" (result), "=&r" (tmp)
+       : "r" (&ptr->counter), "r" (new)
+       : "cc");
+
+       smp_mb();
+
+       return result;
+}
+
+static inline u64 atomic64_dec_if_positive(atomic64_t *v)
+{
+       u64 result;
+       unsigned long tmp;
+
+       smp_mb();
+
+       __asm__ __volatile__("@ atomic64_dec_if_positive\n"
+"1:    ldrexd  %0, %H0, [%2]\n"
+"      subs    %0, %0, #1\n"
+"      sbc     %H0, %H0, #0\n"
+"      teq     %H0, #0\n"
+"      bmi     2f\n"
+"      strexd  %1, %0, %H0, [%2]\n"
+"      teq     %1, #0\n"
+"      bne     1b\n"
+"2:"
+       : "=&r" (result), "=&r" (tmp)
+       : "r" (&v->counter)
+       : "cc");
+
+       smp_mb();
+
+       return result;
+}
+
+static inline int atomic64_add_unless(atomic64_t *v, u64 a, u64 u)
+{
+       u64 val;
+       unsigned long tmp;
+       int ret = 1;
+
+       smp_mb();
+
+       __asm__ __volatile__("@ atomic64_add_unless\n"
+"1:    ldrexd  %0, %H0, [%3]\n"
+"      teq     %0, %4\n"
+"      teqeq   %H0, %H4\n"
+"      moveq   %1, #0\n"
+"      beq     2f\n"
+"      adds    %0, %0, %5\n"
+"      adc     %H0, %H0, %H5\n"
+"      strexd  %2, %0, %H0, [%3]\n"
+"      teq     %2, #0\n"
+"      bne     1b\n"
+"2:"
+       : "=&r" (val), "=&r" (ret), "=&r" (tmp)
+       : "r" (&v->counter), "r" (u), "r" (a)
+       : "cc");
+
+       if (ret)
+               smp_mb();
+
+       return ret;
+}
+
+#define atomic64_add_negative(a, v)    (atomic64_add_return((a), (v)) < 0)
+#define atomic64_inc(v)                        atomic64_add(1LL, (v))
+#define atomic64_inc_return(v)         atomic64_add_return(1LL, (v))
+#define atomic64_inc_and_test(v)       (atomic64_inc_return(v) == 0)
+#define atomic64_sub_and_test(a, v)    (atomic64_sub_return((a), (v)) == 0)
+#define atomic64_dec(v)                        atomic64_sub(1LL, (v))
+#define atomic64_dec_return(v)         atomic64_sub_return(1LL, (v))
+#define atomic64_dec_and_test(v)       (atomic64_dec_return((v)) == 0)
+#define atomic64_inc_not_zero(v)       atomic64_add_unless((v), 1LL, 0LL)
+
+#else /* !CONFIG_GENERIC_ATOMIC64 */
+#include <asm-generic/atomic64.h>
+#endif
 #include <asm-generic/atomic-long.h>
 #endif
 #endif
index 5fe4a2ad7fa34deb2e7be770fdfa782359f6d245..72da7e045c6b306e4d2d40bbad1db22a603f4ed7 100644 (file)
  *     DMA Cache Coherency
  *     ===================
  *
- *     dma_inv_range(start, end)
- *
- *             Invalidate (discard) the specified virtual address range.
- *             May not write back any entries.  If 'start' or 'end'
- *             are not cache line aligned, those lines must be written
- *             back.
- *             - start  - virtual start address
- *             - end    - virtual end address
- *
- *     dma_clean_range(start, end)
- *
- *             Clean (write back) the specified virtual address range.
- *             - start  - virtual start address
- *             - end    - virtual end address
- *
  *     dma_flush_range(start, end)
  *
  *             Clean and invalidate the specified virtual address range.
@@ -228,8 +213,9 @@ struct cpu_cache_fns {
        void (*coherent_user_range)(unsigned long, unsigned long);
        void (*flush_kern_dcache_area)(void *, size_t);
 
-       void (*dma_inv_range)(const void *, const void *);
-       void (*dma_clean_range)(const void *, const void *);
+       void (*dma_map_area)(const void *, size_t, int);
+       void (*dma_unmap_area)(const void *, size_t, int);
+
        void (*dma_flush_range)(const void *, const void *);
 };
 
@@ -259,8 +245,8 @@ extern struct cpu_cache_fns cpu_cache;
  * is visible to DMA, or data written by DMA to system memory is
  * visible to the CPU.
  */
-#define dmac_inv_range                 cpu_cache.dma_inv_range
-#define dmac_clean_range               cpu_cache.dma_clean_range
+#define dmac_map_area                  cpu_cache.dma_map_area
+#define dmac_unmap_area                cpu_cache.dma_unmap_area
 #define dmac_flush_range               cpu_cache.dma_flush_range
 
 #else
@@ -285,12 +271,12 @@ extern void __cpuc_flush_dcache_area(void *, size_t);
  * is visible to DMA, or data written by DMA to system memory is
  * visible to the CPU.
  */
-#define dmac_inv_range                 __glue(_CACHE,_dma_inv_range)
-#define dmac_clean_range               __glue(_CACHE,_dma_clean_range)
+#define dmac_map_area                  __glue(_CACHE,_dma_map_area)
+#define dmac_unmap_area                __glue(_CACHE,_dma_unmap_area)
 #define dmac_flush_range               __glue(_CACHE,_dma_flush_range)
 
-extern void dmac_inv_range(const void *, const void *);
-extern void dmac_clean_range(const void *, const void *);
+extern void dmac_map_area(const void *, size_t, int);
+extern void dmac_unmap_area(const void *, size_t, int);
 extern void dmac_flush_range(const void *, const void *);
 
 #endif
@@ -331,12 +317,8 @@ static inline void outer_flush_range(unsigned long start, unsigned long end)
  * processes address space.  Really, we want to allow our "user
  * space" model to handle this.
  */
-#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
-       do {                                                    \
-               memcpy(dst, src, len);                          \
-               flush_ptrace_access(vma, page, vaddr, dst, len, 1);\
-       } while (0)
-
+extern void copy_to_user_page(struct vm_area_struct *, struct page *,
+       unsigned long, void *, const void *, unsigned long);
 #define copy_from_user_page(vma, page, vaddr, dst, src, len) \
        do {                                                    \
                memcpy(dst, src, len);                          \
@@ -370,17 +352,6 @@ vivt_flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsig
        }
 }
 
-static inline void
-vivt_flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
-                        unsigned long uaddr, void *kaddr,
-                        unsigned long len, int write)
-{
-       if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) {
-               unsigned long addr = (unsigned long)kaddr;
-               __cpuc_coherent_kern_range(addr, addr + len);
-       }
-}
-
 #ifndef CONFIG_CPU_CACHE_VIPT
 #define flush_cache_mm(mm) \
                vivt_flush_cache_mm(mm)
@@ -388,15 +359,10 @@ vivt_flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
                vivt_flush_cache_range(vma,start,end)
 #define flush_cache_page(vma,addr,pfn) \
                vivt_flush_cache_page(vma,addr,pfn)
-#define flush_ptrace_access(vma,page,ua,ka,len,write) \
-               vivt_flush_ptrace_access(vma,page,ua,ka,len,write)
 #else
 extern void flush_cache_mm(struct mm_struct *mm);
 extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
 extern void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned long pfn);
-extern void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
-                               unsigned long uaddr, void *kaddr,
-                               unsigned long len, int write);
 #endif
 
 #define flush_cache_dup_mm(mm) flush_cache_mm(mm)
index b6ec7c627b393a794d1cfaf5549113d51057a7bc..7a0690da5e63235b6a8b1345adc2f396b29287c8 100644 (file)
@@ -27,4 +27,7 @@ struct clk_lookup *clkdev_alloc(struct clk *clk, const char *con_id,
 void clkdev_add(struct clk_lookup *cl);
 void clkdev_drop(struct clk_lookup *cl);
 
+void clkdev_add_table(struct clk_lookup *, size_t);
+int clk_add_alias(const char *, const char *, char *, struct device *);
+
 #endif
index a96300bf83fd65f3c6058da9194eb71ef5e5a35f..256ee1c9f51aae017d2cef9139965aa3d4512cc9 100644 (file)
@@ -57,18 +57,58 @@ static inline dma_addr_t virt_to_dma(struct device *dev, void *addr)
 #endif
 
 /*
- * DMA-consistent mapping functions.  These allocate/free a region of
- * uncached, unwrite-buffered mapped memory space for use with DMA
- * devices.  This is the "generic" version.  The PCI specific version
- * is in pci.h
+ * The DMA API is built upon the notion of "buffer ownership".  A buffer
+ * is either exclusively owned by the CPU (and therefore may be accessed
+ * by it) or exclusively owned by the DMA device.  These helper functions
+ * represent the transitions between these two ownership states.
  *
- * Note: Drivers should NOT use this function directly, as it will break
- * platforms with CONFIG_DMABOUNCE.
- * Use the driver DMA support - see dma-mapping.h (dma_sync_*)
+ * Note, however, that on later ARMs, this notion does not work due to
+ * speculative prefetches.  We model our approach on the assumption that
+ * the CPU does do speculative prefetches, which means we clean caches
+ * before transfers and delay cache invalidation until transfer completion.
+ *
+ * Private support functions: these are not part of the API and are
+ * liable to change.  Drivers must not use these.
  */
-extern void dma_cache_maint(const void *kaddr, size_t size, int rw);
-extern void dma_cache_maint_page(struct page *page, unsigned long offset,
-                                size_t size, int rw);
+static inline void __dma_single_cpu_to_dev(const void *kaddr, size_t size,
+       enum dma_data_direction dir)
+{
+       extern void ___dma_single_cpu_to_dev(const void *, size_t,
+               enum dma_data_direction);
+
+       if (!arch_is_coherent())
+               ___dma_single_cpu_to_dev(kaddr, size, dir);
+}
+
+static inline void __dma_single_dev_to_cpu(const void *kaddr, size_t size,
+       enum dma_data_direction dir)
+{
+       extern void ___dma_single_dev_to_cpu(const void *, size_t,
+               enum dma_data_direction);
+
+       if (!arch_is_coherent())
+               ___dma_single_dev_to_cpu(kaddr, size, dir);
+}
+
+static inline void __dma_page_cpu_to_dev(struct page *page, unsigned long off,
+       size_t size, enum dma_data_direction dir)
+{
+       extern void ___dma_page_cpu_to_dev(struct page *, unsigned long,
+               size_t, enum dma_data_direction);
+
+       if (!arch_is_coherent())
+               ___dma_page_cpu_to_dev(page, off, size, dir);
+}
+
+static inline void __dma_page_dev_to_cpu(struct page *page, unsigned long off,
+       size_t size, enum dma_data_direction dir)
+{
+       extern void ___dma_page_dev_to_cpu(struct page *, unsigned long,
+               size_t, enum dma_data_direction);
+
+       if (!arch_is_coherent())
+               ___dma_page_dev_to_cpu(page, off, size, dir);
+}
 
 /*
  * Return whether the given device DMA address mask can be supported
@@ -304,8 +344,7 @@ static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
 {
        BUG_ON(!valid_dma_direction(dir));
 
-       if (!arch_is_coherent())
-               dma_cache_maint(cpu_addr, size, dir);
+       __dma_single_cpu_to_dev(cpu_addr, size, dir);
 
        return virt_to_dma(dev, cpu_addr);
 }
@@ -329,8 +368,7 @@ static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
 {
        BUG_ON(!valid_dma_direction(dir));
 
-       if (!arch_is_coherent())
-               dma_cache_maint_page(page, offset, size, dir);
+       __dma_page_cpu_to_dev(page, offset, size, dir);
 
        return page_to_dma(dev, page) + offset;
 }
@@ -352,7 +390,7 @@ static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
 static inline void dma_unmap_single(struct device *dev, dma_addr_t handle,
                size_t size, enum dma_data_direction dir)
 {
-       /* nothing to do */
+       __dma_single_dev_to_cpu(dma_to_virt(dev, handle), size, dir);
 }
 
 /**
@@ -372,7 +410,8 @@ static inline void dma_unmap_single(struct device *dev, dma_addr_t handle,
 static inline void dma_unmap_page(struct device *dev, dma_addr_t handle,
                size_t size, enum dma_data_direction dir)
 {
-       /* nothing to do */
+       __dma_page_dev_to_cpu(dma_to_page(dev, handle), handle & ~PAGE_MASK,
+               size, dir);
 }
 #endif /* CONFIG_DMABOUNCE */
 
@@ -400,7 +439,10 @@ static inline void dma_sync_single_range_for_cpu(struct device *dev,
 {
        BUG_ON(!valid_dma_direction(dir));
 
-       dmabounce_sync_for_cpu(dev, handle, offset, size, dir);
+       if (!dmabounce_sync_for_cpu(dev, handle, offset, size, dir))
+               return;
+
+       __dma_single_dev_to_cpu(dma_to_virt(dev, handle) + offset, size, dir);
 }
 
 static inline void dma_sync_single_range_for_device(struct device *dev,
@@ -412,8 +454,7 @@ static inline void dma_sync_single_range_for_device(struct device *dev,
        if (!dmabounce_sync_for_device(dev, handle, offset, size, dir))
                return;
 
-       if (!arch_is_coherent())
-               dma_cache_maint(dma_to_virt(dev, handle) + offset, size, dir);
+       __dma_single_cpu_to_dev(dma_to_virt(dev, handle) + offset, size, dir);
 }
 
 static inline void dma_sync_single_for_cpu(struct device *dev,
index d2a59cfc30ce3f790ccc3b01a781f4fdf75c8baf..c980156f32638f8f031b93e730d0c2e8396aec40 100644 (file)
@@ -69,9 +69,16 @@ extern void __raw_readsl(const void __iomem *addr, void *data, int longlen);
 /*
  * __arm_ioremap takes CPU physical address.
  * __arm_ioremap_pfn takes a Page Frame Number and an offset into that page
+ * The _caller variety takes a __builtin_return_address(0) value for
+ * /proc/vmalloc to use - and should only be used in non-inline functions.
  */
-extern void __iomem * __arm_ioremap_pfn(unsigned long, unsigned long, size_t, unsigned int);
-extern void __iomem * __arm_ioremap(unsigned long, size_t, unsigned int);
+extern void __iomem *__arm_ioremap_pfn_caller(unsigned long, unsigned long,
+       size_t, unsigned int, void *);
+extern void __iomem *__arm_ioremap_caller(unsigned long, size_t, unsigned int,
+       void *);
+
+extern void __iomem *__arm_ioremap_pfn(unsigned long, unsigned long, size_t, unsigned int);
+extern void __iomem *__arm_ioremap(unsigned long, size_t, unsigned int);
 extern void __iounmap(volatile void __iomem *addr);
 
 /*
index b2cc1fcd040059f2381c8491dfe0d94568615372..8bffc3ff3acf794c0b3c046d89017067eeb10617 100644 (file)
@@ -46,12 +46,4 @@ struct sys_timer {
 extern struct sys_timer *system_timer;
 extern void timer_tick(void);
 
-/*
- * Kernel time keeping support.
- */
-struct timespec;
-extern int (*set_rtc)(void);
-extern void save_time_delta(struct timespec *delta, struct timespec *rtc);
-extern void restore_time_delta(struct timespec *delta, struct timespec *rtc);
-
 #endif
index 5421d82a2572475667189fd1e93e07e19359de25..4312ee5e3d0b6d97b83f0655435c7514d43da671 100644 (file)
  */
 #define IOREMAP_MAX_ORDER      24
 
+/*
+ * Size of DMA-consistent memory region.  Must be multiple of 2M,
+ * between 2MB and 14MB inclusive.
+ */
+#ifndef CONSISTENT_DMA_SIZE
+#define CONSISTENT_DMA_SIZE    SZ_2M
+#endif
+
+#define CONSISTENT_END         (0xffe00000UL)
+#define CONSISTENT_BASE                (CONSISTENT_END - CONSISTENT_DMA_SIZE)
+
 #else /* CONFIG_MMU */
 
 /*
 #endif
 
 #ifndef PHYS_OFFSET
-#define PHYS_OFFSET            (CONFIG_DRAM_BASE)
+#define PHYS_OFFSET            UL(CONFIG_DRAM_BASE)
 #endif
 
 #ifndef END_MEM
-#define END_MEM                (CONFIG_DRAM_BASE + CONFIG_DRAM_SIZE)
+#define END_MEM                (UL(CONFIG_DRAM_BASE) + CONFIG_DRAM_SIZE)
 #endif
 
 #ifndef PAGE_OFFSET
 
 #endif /* !CONFIG_MMU */
 
-/*
- * Size of DMA-consistent memory region.  Must be multiple of 2M,
- * between 2MB and 14MB inclusive.
- */
-#ifndef CONSISTENT_DMA_SIZE
-#define CONSISTENT_DMA_SIZE SZ_2M
-#endif
-
 /*
  * Physical vs virtual RAM address space conversion.  These are
  * private definitions which should NOT be used outside memory.h
index b561584d04a18ef6c631d1e05d69f6ff4b22d194..68870c7766712a4778b32278e64f82484d12f5e5 100644 (file)
@@ -6,6 +6,7 @@
 typedef struct {
 #ifdef CONFIG_CPU_HAS_ASID
        unsigned int id;
+       spinlock_t id_lock;
 #endif
        unsigned int kvm_seq;
 } mm_context_t;
index de6cefb329dd4aa24cd42731730915938a33aaf4..a0b3cac0547c0a9949c30cc919adcf5e08fcf500 100644 (file)
@@ -43,12 +43,23 @@ void __check_kvm_seq(struct mm_struct *mm);
 #define ASID_FIRST_VERSION     (1 << ASID_BITS)
 
 extern unsigned int cpu_last_asid;
+#ifdef CONFIG_SMP
+DECLARE_PER_CPU(struct mm_struct *, current_mm);
+#endif
 
 void __init_new_context(struct task_struct *tsk, struct mm_struct *mm);
 void __new_context(struct mm_struct *mm);
 
 static inline void check_context(struct mm_struct *mm)
 {
+       /*
+        * This code is executed with interrupts enabled. Therefore,
+        * mm->context.id cannot be updated to the latest ASID version
+        * on a different CPU (and condition below not triggered)
+        * without first getting an IPI to reset the context. The
+        * alternative is to take a read_lock on mm->context.id_lock
+        * (after changing its type to rwlock_t).
+        */
        if (unlikely((mm->context.id ^ cpu_last_asid) >> ASID_BITS))
                __new_context(mm);
 
@@ -108,6 +119,10 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
                __flush_icache_all();
 #endif
        if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next)) || prev != next) {
+#ifdef CONFIG_SMP
+               struct mm_struct **crt_mm = &per_cpu(current_mm, cpu);
+               *crt_mm = next;
+#endif
                check_context(next);
                cpu_switch_mm(next->pgd, next);
                if (cache_is_vivt())
index 3a32af4cce30ac2ec0da9eb3089cbcf0082b193f..a485ac3c8696d2cdbc2e9a857ba4298de63e1428 100644 (file)
 #endif
 
 struct page;
+struct vm_area_struct;
 
 struct cpu_user_fns {
        void (*cpu_clear_user_highpage)(struct page *page, unsigned long vaddr);
        void (*cpu_copy_user_highpage)(struct page *to, struct page *from,
-                       unsigned long vaddr);
+                       unsigned long vaddr, struct vm_area_struct *vma);
 };
 
 #ifdef MULTI_USER
@@ -137,7 +138,7 @@ extern struct cpu_user_fns cpu_user;
 
 extern void __cpu_clear_user_highpage(struct page *page, unsigned long vaddr);
 extern void __cpu_copy_user_highpage(struct page *to, struct page *from,
-                       unsigned long vaddr);
+                       unsigned long vaddr, struct vm_area_struct *vma);
 #endif
 
 #define clear_user_highpage(page,vaddr)                \
@@ -145,7 +146,7 @@ extern void __cpu_copy_user_highpage(struct page *to, struct page *from,
 
 #define __HAVE_ARCH_COPY_USER_HIGHPAGE
 #define copy_user_highpage(to,from,vaddr,vma)  \
-       __cpu_copy_user_highpage(to, from, vaddr)
+       __cpu_copy_user_highpage(to, from, vaddr, vma)
 
 #define clear_page(page)       memset((void *)(page), 0, PAGE_SIZE)
 extern void copy_page(void *to, const void *from);
diff --git a/arch/arm/include/asm/perf_event.h b/arch/arm/include/asm/perf_event.h
new file mode 100644 (file)
index 0000000..49e3049
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ *  linux/arch/arm/include/asm/perf_event.h
+ *
+ *  Copyright (C) 2009 picoChip Designs Ltd, Jamie Iles
+ *
+ * This program is free software; you can 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 __ARM_PERF_EVENT_H__
+#define __ARM_PERF_EVENT_H__
+
+/*
+ * NOP: on *most* (read: all supported) ARM platforms, the performance
+ * counter interrupts are regular interrupts and not an NMI. This
+ * means that when we receive the interrupt we can call
+ * perf_event_do_pending() that handles all of the work with
+ * interrupts enabled.
+ */
+static inline void
+set_perf_event_pending(void)
+{
+}
+
+/* ARM performance counters start from 1 (in the cp15 accesses) so use the
+ * same indexes here for consistency. */
+#define PERF_EVENT_INDEX_OFFSET 1
+
+#endif /* __ARM_PERF_EVENT_H__ */
index b011f2e939aa703da1366306bfa75a980d217c37..013cfcdc4839a2df6b5f0e842515c0a0c166f524 100644 (file)
@@ -86,8 +86,8 @@ extern unsigned int kobjsize(const void *objp);
  * All 32bit addresses are effectively valid for vmalloc...
  * Sort of meaningless for non-VM targets.
  */
-#define        VMALLOC_START   0
-#define        VMALLOC_END     0xffffffff
+#define        VMALLOC_START   0UL
+#define        VMALLOC_END     0xffffffffUL
 
 #define FIRST_USER_ADDRESS      (0)
 
diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h
new file mode 100644 (file)
index 0000000..2829b9f
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ *  linux/arch/arm/include/asm/pmu.h
+ *
+ *  Copyright (C) 2009 picoChip Designs Ltd, Jamie Iles
+ *
+ * This program is free software; you can 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 __ARM_PMU_H__
+#define __ARM_PMU_H__
+
+#ifdef CONFIG_CPU_HAS_PMU
+
+struct pmu_irqs {
+       const int   *irqs;
+       int         num_irqs;
+};
+
+/**
+ * reserve_pmu() - reserve the hardware performance counters
+ *
+ * Reserve the hardware performance counters in the system for exclusive use.
+ * The 'struct pmu_irqs' for the system is returned on success, ERR_PTR()
+ * encoded error on failure.
+ */
+extern const struct pmu_irqs *
+reserve_pmu(void);
+
+/**
+ * release_pmu() - Relinquish control of the performance counters
+ *
+ * Release the performance counters and allow someone else to use them.
+ * Callers must have disabled the counters and released IRQs before calling
+ * this. The 'struct pmu_irqs' returned from reserve_pmu() must be passed as
+ * a cookie.
+ */
+extern int
+release_pmu(const struct pmu_irqs *irqs);
+
+/**
+ * init_pmu() - Initialise the PMU.
+ *
+ * Initialise the system ready for PMU enabling. This should typically set the
+ * IRQ affinity and nothing else. The users (oprofile/perf events etc) will do
+ * the actual hardware initialisation.
+ */
+extern int
+init_pmu(void);
+
+#else /* CONFIG_CPU_HAS_PMU */
+
+static inline const struct pmu_irqs *
+reserve_pmu(void)
+{
+       return ERR_PTR(-ENODEV);
+}
+
+static inline int
+release_pmu(const struct pmu_irqs *irqs)
+{
+       return -ENODEV;
+}
+
+static inline int
+init_pmu(void)
+{
+       return -ENODEV;
+}
+
+#endif /* CONFIG_CPU_HAS_PMU */
+
+#endif /* __ARM_PMU_H__ */
index 5ccce0a9b03cdfd6a054b4c43b429d3bbce922d9..f392fb4437afbd86b35807f16a152ab773df17f4 100644 (file)
@@ -223,18 +223,6 @@ extern struct meminfo meminfo;
 #define bank_phys_end(bank)    ((bank)->start + (bank)->size)
 #define bank_phys_size(bank)   (bank)->size
 
-/*
- * Early command line parameters.
- */
-struct early_params {
-       const char *arg;
-       void (*fn)(char **p);
-};
-
-#define __early_param(name,fn)                                 \
-static struct early_params __early_##fn __used                 \
-__attribute__((__section__(".early_param.init"))) = { name, fn }
-
 #endif  /*  __KERNEL__  */
 
 #endif
index 59303e2008457763334a6e2306de382280030ab7..e6215305544aa9c63db768c53a7c194fe38c6747 100644 (file)
@@ -13,4 +13,9 @@ static inline int tlb_ops_need_broadcast(void)
        return ((read_cpuid_ext(CPUID_EXT_MMFR3) >> 12) & 0xf) < 2;
 }
 
+static inline int cache_ops_need_broadcast(void)
+{
+       return ((read_cpuid_ext(CPUID_EXT_MMFR3) >> 12) & 0xf) < 1;
+}
+
 #endif
index c91c64cab922c908186511a530f72673dd82d3b0..17eb355707dd321643ed995e848d4cebcb087508 100644 (file)
@@ -5,6 +5,22 @@
 #error SMP not supported on pre-ARMv6 CPUs
 #endif
 
+static inline void dsb_sev(void)
+{
+#if __LINUX_ARM_ARCH__ >= 7
+       __asm__ __volatile__ (
+               "dsb\n"
+               "sev"
+       );
+#elif defined(CONFIG_CPU_32v6K)
+       __asm__ __volatile__ (
+               "mcr p15, 0, %0, c7, c10, 4\n"
+               "sev"
+               : : "r" (0)
+       );
+#endif
+}
+
 /*
  * ARMv6 Spin-locking.
  *
@@ -69,13 +85,11 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
 
        __asm__ __volatile__(
 "      str     %1, [%0]\n"
-#ifdef CONFIG_CPU_32v6K
-"      mcr     p15, 0, %1, c7, c10, 4\n" /* DSB */
-"      sev"
-#endif
        :
        : "r" (&lock->lock), "r" (0)
        : "cc");
+
+       dsb_sev();
 }
 
 /*
@@ -132,13 +146,11 @@ static inline void arch_write_unlock(arch_rwlock_t *rw)
 
        __asm__ __volatile__(
        "str    %1, [%0]\n"
-#ifdef CONFIG_CPU_32v6K
-"      mcr     p15, 0, %1, c7, c10, 4\n" /* DSB */
-"      sev\n"
-#endif
        :
        : "r" (&rw->lock), "r" (0)
        : "cc");
+
+       dsb_sev();
 }
 
 /* write_can_lock - would write_trylock() succeed? */
@@ -188,14 +200,12 @@ static inline void arch_read_unlock(arch_rwlock_t *rw)
 "      strex   %1, %0, [%2]\n"
 "      teq     %1, #0\n"
 "      bne     1b"
-#ifdef CONFIG_CPU_32v6K
-"\n    cmp     %0, #0\n"
-"      mcreq   p15, 0, %0, c7, c10, 4\n"
-"      seveq"
-#endif
        : "=&r" (tmp), "=&r" (tmp2)
        : "r" (&rw->lock)
        : "cc");
+
+       if (tmp == 0)
+               dsb_sev();
 }
 
 static inline int arch_read_trylock(arch_rwlock_t *rw)
index 058e7e90881d6a86103df826f43ec9ab2563682b..ca88e6a84707350bad0b1ab3bd7eefcd116be506 100644 (file)
@@ -73,8 +73,7 @@ extern unsigned int mem_fclk_21285;
 
 struct pt_regs;
 
-void die(const char *msg, struct pt_regs *regs, int err)
-               __attribute__((noreturn));
+void die(const char *msg, struct pt_regs *regs, int err);
 
 struct siginfo;
 void arm_notify_die(const char *str, struct pt_regs *regs, struct siginfo *info,
index 2dfb7d7a66e988b285629011527c406d00a94cc5..b74970ec02c4431ae1636289ffb3728d5d6bcc8f 100644 (file)
@@ -115,7 +115,8 @@ extern void iwmmxt_task_restore(struct thread_info *, void *);
 extern void iwmmxt_task_release(struct thread_info *);
 extern void iwmmxt_task_switch(struct thread_info *);
 
-extern void vfp_sync_state(struct thread_info *thread);
+extern void vfp_sync_hwstate(struct thread_info *);
+extern void vfp_flush_hwstate(struct thread_info *);
 
 #endif
 
index c2f1605de35902df4378b1e77898cc796441b4db..e085e2c545ebabad792dfa6e25fb149eb3cada27 100644 (file)
@@ -529,7 +529,8 @@ extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
  * cache entries for the kernels virtual memory range are written
  * back to the page.
  */
-extern void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte);
+extern void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr,
+       pte_t *ptep);
 
 #endif
 
index dd00f747e2ad00aeb844dd6b8c8373dd34b2a853..26d302c28e1318b4aa5db81a491fcd6a82b0e6fa 100644 (file)
@@ -17,6 +17,7 @@ obj-y         := compat.o elf.o entry-armv.o entry-common.o irq.o \
                   process.o ptrace.o return_address.o setup.o signal.o \
                   sys_arm.o stacktrace.o time.o traps.o
 
+obj-$(CONFIG_LEDS)             += leds.o
 obj-$(CONFIG_OC_ETM)           += etm.o
 
 obj-$(CONFIG_ISA_DMA_API)      += dma.o
@@ -46,6 +47,8 @@ obj-$(CONFIG_CPU_XSCALE)      += xscale-cp0.o
 obj-$(CONFIG_CPU_XSC3)         += xscale-cp0.o
 obj-$(CONFIG_CPU_MOHAWK)       += xscale-cp0.o
 obj-$(CONFIG_IWMMXT)           += iwmmxt.o
+obj-$(CONFIG_CPU_HAS_PMU)      += pmu.o
+obj-$(CONFIG_HW_PERF_EVENTS)   += perf_event.o
 AFLAGS_iwmmxt.o                        := -Wa,-mcpu=iwmmxt
 
 ifneq ($(CONFIG_ARCH_EBSA110),y)
index 4a881258bb171f7c14828d12fdc4ef9bf91b0186..883511522fca9e83be970c2611fd2ce5a1a75a41 100644 (file)
@@ -12,6 +12,7 @@
  */
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/dma-mapping.h>
 #include <asm/mach/arch.h>
 #include <asm/thread_info.h>
 #include <asm/memory.h>
@@ -112,5 +113,9 @@ int main(void)
 #ifdef MULTI_PABORT
   DEFINE(PROCESSOR_PABT_FUNC,  offsetof(struct processor, _prefetch_abort));
 #endif
+  BLANK();
+  DEFINE(DMA_BIDIRECTIONAL,    DMA_BIDIRECTIONAL);
+  DEFINE(DMA_TO_DEVICE,                DMA_TO_DEVICE);
+  DEFINE(DMA_FROM_DEVICE,      DMA_FROM_DEVICE);
   return 0; 
 }
index 5c91addcaebcb2d8d207a4deb920e3cb7ea48729..a38b4879441d1715b42c4e7994f9f4d8e67b7fe4 100644 (file)
@@ -24,7 +24,7 @@
 
 #if defined(CONFIG_CPU_V6)
 
-               .macro  addruart, rx
+               .macro  addruart, rx, tmp
                .endm
 
                .macro  senduart, rd, rx
@@ -51,7 +51,7 @@
 
 #elif defined(CONFIG_CPU_V7)
 
-               .macro  addruart, rx
+               .macro  addruart, rx, tmp
                .endm
 
                .macro  senduart, rd, rx
@@ -71,7 +71,7 @@ wait:         mrc     p14, 0, pc, c0, c1, 0
 
 #elif defined(CONFIG_CPU_XSCALE)
 
-               .macro  addruart, rx
+               .macro  addruart, rx, tmp
                .endm
 
                .macro  senduart, rd, rx
@@ -98,7 +98,7 @@ wait:         mrc     p14, 0, pc, c0, c1, 0
 
 #else
 
-               .macro  addruart, rx
+               .macro  addruart, rx, tmp
                .endm
 
                .macro  senduart, rd, rx
@@ -164,7 +164,7 @@ ENDPROC(printhex2)
                .ltorg
 
 ENTRY(printascii)
-               addruart r3
+               addruart r3, r1
                b       2f
 1:             waituart r2, r3
                senduart r1, r3
@@ -180,7 +180,7 @@ ENTRY(printascii)
 ENDPROC(printascii)
 
 ENTRY(printch)
-               addruart r3
+               addruart r3, r1
                mov     r1, r0
                mov     r0, #0
                b       1b
diff --git a/arch/arm/kernel/leds.c b/arch/arm/kernel/leds.c
new file mode 100644 (file)
index 0000000..31a316c
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * LED support code, ripped out of arch/arm/kernel/time.c
+ *
+ *  Copyright (C) 1994-2001 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sysdev.h>
+
+#include <asm/leds.h>
+
+static void dummy_leds_event(led_event_t evt)
+{
+}
+
+void (*leds_event)(led_event_t) = dummy_leds_event;
+
+struct leds_evt_name {
+       const char      name[8];
+       int             on;
+       int             off;
+};
+
+static const struct leds_evt_name evt_names[] = {
+       { "amber", led_amber_on, led_amber_off },
+       { "blue",  led_blue_on,  led_blue_off  },
+       { "green", led_green_on, led_green_off },
+       { "red",   led_red_on,   led_red_off   },
+};
+
+static ssize_t leds_store(struct sys_device *dev,
+                       struct sysdev_attribute *attr,
+                       const char *buf, size_t size)
+{
+       int ret = -EINVAL, len = strcspn(buf, " ");
+
+       if (len > 0 && buf[len] == '\0')
+               len--;
+
+       if (strncmp(buf, "claim", len) == 0) {
+               leds_event(led_claim);
+               ret = size;
+       } else if (strncmp(buf, "release", len) == 0) {
+               leds_event(led_release);
+               ret = size;
+       } else {
+               int i;
+
+               for (i = 0; i < ARRAY_SIZE(evt_names); i++) {
+                       if (strlen(evt_names[i].name) != len ||
+                           strncmp(buf, evt_names[i].name, len) != 0)
+                               continue;
+                       if (strncmp(buf+len, " on", 3) == 0) {
+                               leds_event(evt_names[i].on);
+                               ret = size;
+                       } else if (strncmp(buf+len, " off", 4) == 0) {
+                               leds_event(evt_names[i].off);
+                               ret = size;
+                       }
+                       break;
+               }
+       }
+       return ret;
+}
+
+static SYSDEV_ATTR(event, 0200, NULL, leds_store);
+
+static int leds_suspend(struct sys_device *dev, pm_message_t state)
+{
+       leds_event(led_stop);
+       return 0;
+}
+
+static int leds_resume(struct sys_device *dev)
+{
+       leds_event(led_start);
+       return 0;
+}
+
+static int leds_shutdown(struct sys_device *dev)
+{
+       leds_event(led_halted);
+       return 0;
+}
+
+static struct sysdev_class leds_sysclass = {
+       .name           = "leds",
+       .shutdown       = leds_shutdown,
+       .suspend        = leds_suspend,
+       .resume         = leds_resume,
+};
+
+static struct sys_device leds_device = {
+       .id             = 0,
+       .cls            = &leds_sysclass,
+};
+
+static int __init leds_init(void)
+{
+       int ret;
+       ret = sysdev_class_register(&leds_sysclass);
+       if (ret == 0)
+               ret = sysdev_register(&leds_device);
+       if (ret == 0)
+               ret = sysdev_create_file(&leds_device, &attr_event);
+       return ret;
+}
+
+device_initcall(leds_init);
+
+EXPORT_SYMBOL(leds_event);
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
new file mode 100644 (file)
index 0000000..c54ceb3
--- /dev/null
@@ -0,0 +1,2276 @@
+#undef DEBUG
+
+/*
+ * ARM performance counter support.
+ *
+ * Copyright (C) 2009 picoChip Designs, Ltd., Jamie Iles
+ *
+ * ARMv7 support: Jean Pihet <jpihet@mvista.com>
+ * 2010 (c) MontaVista Software, LLC.
+ *
+ * This code is based on the sparc64 perf event code, which is in turn based
+ * on the x86 code. Callchain code is based on the ARM OProfile backtrace
+ * code.
+ */
+#define pr_fmt(fmt) "hw perfevents: " fmt
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/perf_event.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+
+#include <asm/cputype.h>
+#include <asm/irq.h>
+#include <asm/irq_regs.h>
+#include <asm/pmu.h>
+#include <asm/stacktrace.h>
+
+static const struct pmu_irqs *pmu_irqs;
+
+/*
+ * Hardware lock to serialize accesses to PMU registers. Needed for the
+ * read/modify/write sequences.
+ */
+DEFINE_SPINLOCK(pmu_lock);
+
+/*
+ * ARMv6 supports a maximum of 3 events, starting from index 1. If we add
+ * another platform that supports more, we need to increase this to be the
+ * largest of all platforms.
+ *
+ * ARMv7 supports up to 32 events:
+ *  cycle counter CCNT + 31 events counters CNT0..30.
+ *  Cortex-A8 has 1+4 counters, Cortex-A9 has 1+6 counters.
+ */
+#define ARMPMU_MAX_HWEVENTS            33
+
+/* The events for a given CPU. */
+struct cpu_hw_events {
+       /*
+        * The events that are active on the CPU for the given index. Index 0
+        * is reserved.
+        */
+       struct perf_event       *events[ARMPMU_MAX_HWEVENTS];
+
+       /*
+        * A 1 bit for an index indicates that the counter is being used for
+        * an event. A 0 means that the counter can be used.
+        */
+       unsigned long           used_mask[BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)];
+
+       /*
+        * A 1 bit for an index indicates that the counter is actively being
+        * used.
+        */
+       unsigned long           active_mask[BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)];
+};
+DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
+
+struct arm_pmu {
+       char            *name;
+       irqreturn_t     (*handle_irq)(int irq_num, void *dev);
+       void            (*enable)(struct hw_perf_event *evt, int idx);
+       void            (*disable)(struct hw_perf_event *evt, int idx);
+       int             (*event_map)(int evt);
+       u64             (*raw_event)(u64);
+       int             (*get_event_idx)(struct cpu_hw_events *cpuc,
+                                        struct hw_perf_event *hwc);
+       u32             (*read_counter)(int idx);
+       void            (*write_counter)(int idx, u32 val);
+       void            (*start)(void);
+       void            (*stop)(void);
+       int             num_events;
+       u64             max_period;
+};
+
+/* Set at runtime when we know what CPU type we are. */
+static const struct arm_pmu *armpmu;
+
+#define HW_OP_UNSUPPORTED              0xFFFF
+
+#define C(_x) \
+       PERF_COUNT_HW_CACHE_##_x
+
+#define CACHE_OP_UNSUPPORTED           0xFFFF
+
+static unsigned armpmu_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
+                                    [PERF_COUNT_HW_CACHE_OP_MAX]
+                                    [PERF_COUNT_HW_CACHE_RESULT_MAX];
+
+static int
+armpmu_map_cache_event(u64 config)
+{
+       unsigned int cache_type, cache_op, cache_result, ret;
+
+       cache_type = (config >>  0) & 0xff;
+       if (cache_type >= PERF_COUNT_HW_CACHE_MAX)
+               return -EINVAL;
+
+       cache_op = (config >>  8) & 0xff;
+       if (cache_op >= PERF_COUNT_HW_CACHE_OP_MAX)
+               return -EINVAL;
+
+       cache_result = (config >> 16) & 0xff;
+       if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
+               return -EINVAL;
+
+       ret = (int)armpmu_perf_cache_map[cache_type][cache_op][cache_result];
+
+       if (ret == CACHE_OP_UNSUPPORTED)
+               return -ENOENT;
+
+       return ret;
+}
+
+static int
+armpmu_event_set_period(struct perf_event *event,
+                       struct hw_perf_event *hwc,
+                       int idx)
+{
+       s64 left = atomic64_read(&hwc->period_left);
+       s64 period = hwc->sample_period;
+       int ret = 0;
+
+       if (unlikely(left <= -period)) {
+               left = period;
+               atomic64_set(&hwc->period_left, left);
+               hwc->last_period = period;
+               ret = 1;
+       }
+
+       if (unlikely(left <= 0)) {
+               left += period;
+               atomic64_set(&hwc->period_left, left);
+               hwc->last_period = period;
+               ret = 1;
+       }
+
+       if (left > (s64)armpmu->max_period)
+               left = armpmu->max_period;
+
+       atomic64_set(&hwc->prev_count, (u64)-left);
+
+       armpmu->write_counter(idx, (u64)(-left) & 0xffffffff);
+
+       perf_event_update_userpage(event);
+
+       return ret;
+}
+
+static u64
+armpmu_event_update(struct perf_event *event,
+                   struct hw_perf_event *hwc,
+                   int idx)
+{
+       int shift = 64 - 32;
+       s64 prev_raw_count, new_raw_count;
+       s64 delta;
+
+again:
+       prev_raw_count = atomic64_read(&hwc->prev_count);
+       new_raw_count = armpmu->read_counter(idx);
+
+       if (atomic64_cmpxchg(&hwc->prev_count, prev_raw_count,
+                            new_raw_count) != prev_raw_count)
+               goto again;
+
+       delta = (new_raw_count << shift) - (prev_raw_count << shift);
+       delta >>= shift;
+
+       atomic64_add(delta, &event->count);
+       atomic64_sub(delta, &hwc->period_left);
+
+       return new_raw_count;
+}
+
+static void
+armpmu_disable(struct perf_event *event)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+       struct hw_perf_event *hwc = &event->hw;
+       int idx = hwc->idx;
+
+       WARN_ON(idx < 0);
+
+       clear_bit(idx, cpuc->active_mask);
+       armpmu->disable(hwc, idx);
+
+       barrier();
+
+       armpmu_event_update(event, hwc, idx);
+       cpuc->events[idx] = NULL;
+       clear_bit(idx, cpuc->used_mask);
+
+       perf_event_update_userpage(event);
+}
+
+static void
+armpmu_read(struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       /* Don't read disabled counters! */
+       if (hwc->idx < 0)
+               return;
+
+       armpmu_event_update(event, hwc, hwc->idx);
+}
+
+static void
+armpmu_unthrottle(struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       /*
+        * Set the period again. Some counters can't be stopped, so when we
+        * were throttled we simply disabled the IRQ source and the counter
+        * may have been left counting. If we don't do this step then we may
+        * get an interrupt too soon or *way* too late if the overflow has
+        * happened since disabling.
+        */
+       armpmu_event_set_period(event, hwc, hwc->idx);
+       armpmu->enable(hwc, hwc->idx);
+}
+
+static int
+armpmu_enable(struct perf_event *event)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+       struct hw_perf_event *hwc = &event->hw;
+       int idx;
+       int err = 0;
+
+       /* If we don't have a space for the counter then finish early. */
+       idx = armpmu->get_event_idx(cpuc, hwc);
+       if (idx < 0) {
+               err = idx;
+               goto out;
+       }
+
+       /*
+        * If there is an event in the counter we are going to use then make
+        * sure it is disabled.
+        */
+       event->hw.idx = idx;
+       armpmu->disable(hwc, idx);
+       cpuc->events[idx] = event;
+       set_bit(idx, cpuc->active_mask);
+
+       /* Set the period for the event. */
+       armpmu_event_set_period(event, hwc, idx);
+
+       /* Enable the event. */
+       armpmu->enable(hwc, idx);
+
+       /* Propagate our changes to the userspace mapping. */
+       perf_event_update_userpage(event);
+
+out:
+       return err;
+}
+
+static struct pmu pmu = {
+       .enable     = armpmu_enable,
+       .disable    = armpmu_disable,
+       .unthrottle = armpmu_unthrottle,
+       .read       = armpmu_read,
+};
+
+static int
+validate_event(struct cpu_hw_events *cpuc,
+              struct perf_event *event)
+{
+       struct hw_perf_event fake_event = event->hw;
+
+       if (event->pmu && event->pmu != &pmu)
+               return 0;
+
+       return armpmu->get_event_idx(cpuc, &fake_event) >= 0;
+}
+
+static int
+validate_group(struct perf_event *event)
+{
+       struct perf_event *sibling, *leader = event->group_leader;
+       struct cpu_hw_events fake_pmu;
+
+       memset(&fake_pmu, 0, sizeof(fake_pmu));
+
+       if (!validate_event(&fake_pmu, leader))
+               return -ENOSPC;
+
+       list_for_each_entry(sibling, &leader->sibling_list, group_entry) {
+               if (!validate_event(&fake_pmu, sibling))
+                       return -ENOSPC;
+       }
+
+       if (!validate_event(&fake_pmu, event))
+               return -ENOSPC;
+
+       return 0;
+}
+
+static int
+armpmu_reserve_hardware(void)
+{
+       int i;
+       int err;
+
+       pmu_irqs = reserve_pmu();
+       if (IS_ERR(pmu_irqs)) {
+               pr_warning("unable to reserve pmu\n");
+               return PTR_ERR(pmu_irqs);
+       }
+
+       init_pmu();
+
+       if (pmu_irqs->num_irqs < 1) {
+               pr_err("no irqs for PMUs defined\n");
+               return -ENODEV;
+       }
+
+       for (i = 0; i < pmu_irqs->num_irqs; ++i) {
+               err = request_irq(pmu_irqs->irqs[i], armpmu->handle_irq,
+                                 IRQF_DISABLED, "armpmu", NULL);
+               if (err) {
+                       pr_warning("unable to request IRQ%d for ARM "
+                                  "perf counters\n", pmu_irqs->irqs[i]);
+                       break;
+               }
+       }
+
+       if (err) {
+               for (i = i - 1; i >= 0; --i)
+                       free_irq(pmu_irqs->irqs[i], NULL);
+               release_pmu(pmu_irqs);
+               pmu_irqs = NULL;
+       }
+
+       return err;
+}
+
+static void
+armpmu_release_hardware(void)
+{
+       int i;
+
+       for (i = pmu_irqs->num_irqs - 1; i >= 0; --i)
+               free_irq(pmu_irqs->irqs[i], NULL);
+       armpmu->stop();
+
+       release_pmu(pmu_irqs);
+       pmu_irqs = NULL;
+}
+
+static atomic_t active_events = ATOMIC_INIT(0);
+static DEFINE_MUTEX(pmu_reserve_mutex);
+
+static void
+hw_perf_event_destroy(struct perf_event *event)
+{
+       if (atomic_dec_and_mutex_lock(&active_events, &pmu_reserve_mutex)) {
+               armpmu_release_hardware();
+               mutex_unlock(&pmu_reserve_mutex);
+       }
+}
+
+static int
+__hw_perf_event_init(struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       int mapping, err;
+
+       /* Decode the generic type into an ARM event identifier. */
+       if (PERF_TYPE_HARDWARE == event->attr.type) {
+               mapping = armpmu->event_map(event->attr.config);
+       } else if (PERF_TYPE_HW_CACHE == event->attr.type) {
+               mapping = armpmu_map_cache_event(event->attr.config);
+       } else if (PERF_TYPE_RAW == event->attr.type) {
+               mapping = armpmu->raw_event(event->attr.config);
+       } else {
+               pr_debug("event type %x not supported\n", event->attr.type);
+               return -EOPNOTSUPP;
+       }
+
+       if (mapping < 0) {
+               pr_debug("event %x:%llx not supported\n", event->attr.type,
+                        event->attr.config);
+               return mapping;
+       }
+
+       /*
+        * Check whether we need to exclude the counter from certain modes.
+        * The ARM performance counters are on all of the time so if someone
+        * has asked us for some excludes then we have to fail.
+        */
+       if (event->attr.exclude_kernel || event->attr.exclude_user ||
+           event->attr.exclude_hv || event->attr.exclude_idle) {
+               pr_debug("ARM performance counters do not support "
+                        "mode exclusion\n");
+               return -EPERM;
+       }
+
+       /*
+        * We don't assign an index until we actually place the event onto
+        * hardware. Use -1 to signify that we haven't decided where to put it
+        * yet. For SMP systems, each core has it's own PMU so we can't do any
+        * clever allocation or constraints checking at this point.
+        */
+       hwc->idx = -1;
+
+       /*
+        * Store the event encoding into the config_base field. config and
+        * event_base are unused as the only 2 things we need to know are
+        * the event mapping and the counter to use. The counter to use is
+        * also the indx and the config_base is the event type.
+        */
+       hwc->config_base            = (unsigned long)mapping;
+       hwc->config                 = 0;
+       hwc->event_base             = 0;
+
+       if (!hwc->sample_period) {
+               hwc->sample_period  = armpmu->max_period;
+               hwc->last_period    = hwc->sample_period;
+               atomic64_set(&hwc->period_left, hwc->sample_period);
+       }
+
+       err = 0;
+       if (event->group_leader != event) {
+               err = validate_group(event);
+               if (err)
+                       return -EINVAL;
+       }
+
+       return err;
+}
+
+const struct pmu *
+hw_perf_event_init(struct perf_event *event)
+{
+       int err = 0;
+
+       if (!armpmu)
+               return ERR_PTR(-ENODEV);
+
+       event->destroy = hw_perf_event_destroy;
+
+       if (!atomic_inc_not_zero(&active_events)) {
+               if (atomic_read(&active_events) > perf_max_events) {
+                       atomic_dec(&active_events);
+                       return ERR_PTR(-ENOSPC);
+               }
+
+               mutex_lock(&pmu_reserve_mutex);
+               if (atomic_read(&active_events) == 0) {
+                       err = armpmu_reserve_hardware();
+               }
+
+               if (!err)
+                       atomic_inc(&active_events);
+               mutex_unlock(&pmu_reserve_mutex);
+       }
+
+       if (err)
+               return ERR_PTR(err);
+
+       err = __hw_perf_event_init(event);
+       if (err)
+               hw_perf_event_destroy(event);
+
+       return err ? ERR_PTR(err) : &pmu;
+}
+
+void
+hw_perf_enable(void)
+{
+       /* Enable all of the perf events on hardware. */
+       int idx;
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+
+       if (!armpmu)
+               return;
+
+       for (idx = 0; idx <= armpmu->num_events; ++idx) {
+               struct perf_event *event = cpuc->events[idx];
+
+               if (!event)
+                       continue;
+
+               armpmu->enable(&event->hw, idx);
+       }
+
+       armpmu->start();
+}
+
+void
+hw_perf_disable(void)
+{
+       if (armpmu)
+               armpmu->stop();
+}
+
+/*
+ * ARMv6 Performance counter handling code.
+ *
+ * ARMv6 has 2 configurable performance counters and a single cycle counter.
+ * They all share a single reset bit but can be written to zero so we can use
+ * that for a reset.
+ *
+ * The counters can't be individually enabled or disabled so when we remove
+ * one event and replace it with another we could get spurious counts from the
+ * wrong event. However, we can take advantage of the fact that the
+ * performance counters can export events to the event bus, and the event bus
+ * itself can be monitored. This requires that we *don't* export the events to
+ * the event bus. The procedure for disabling a configurable counter is:
+ *     - change the counter to count the ETMEXTOUT[0] signal (0x20). This
+ *       effectively stops the counter from counting.
+ *     - disable the counter's interrupt generation (each counter has it's
+ *       own interrupt enable bit).
+ * Once stopped, the counter value can be written as 0 to reset.
+ *
+ * To enable a counter:
+ *     - enable the counter's interrupt generation.
+ *     - set the new event type.
+ *
+ * Note: the dedicated cycle counter only counts cycles and can't be
+ * enabled/disabled independently of the others. When we want to disable the
+ * cycle counter, we have to just disable the interrupt reporting and start
+ * ignoring that counter. When re-enabling, we have to reset the value and
+ * enable the interrupt.
+ */
+
+enum armv6_perf_types {
+       ARMV6_PERFCTR_ICACHE_MISS           = 0x0,
+       ARMV6_PERFCTR_IBUF_STALL            = 0x1,
+       ARMV6_PERFCTR_DDEP_STALL            = 0x2,
+       ARMV6_PERFCTR_ITLB_MISS             = 0x3,
+       ARMV6_PERFCTR_DTLB_MISS             = 0x4,
+       ARMV6_PERFCTR_BR_EXEC               = 0x5,
+       ARMV6_PERFCTR_BR_MISPREDICT         = 0x6,
+       ARMV6_PERFCTR_INSTR_EXEC            = 0x7,
+       ARMV6_PERFCTR_DCACHE_HIT            = 0x9,
+       ARMV6_PERFCTR_DCACHE_ACCESS         = 0xA,
+       ARMV6_PERFCTR_DCACHE_MISS           = 0xB,
+       ARMV6_PERFCTR_DCACHE_WBACK          = 0xC,
+       ARMV6_PERFCTR_SW_PC_CHANGE          = 0xD,
+       ARMV6_PERFCTR_MAIN_TLB_MISS         = 0xF,
+       ARMV6_PERFCTR_EXPL_D_ACCESS         = 0x10,
+       ARMV6_PERFCTR_LSU_FULL_STALL        = 0x11,
+       ARMV6_PERFCTR_WBUF_DRAINED          = 0x12,
+       ARMV6_PERFCTR_CPU_CYCLES            = 0xFF,
+       ARMV6_PERFCTR_NOP                   = 0x20,
+};
+
+enum armv6_counters {
+       ARMV6_CYCLE_COUNTER = 1,
+       ARMV6_COUNTER0,
+       ARMV6_COUNTER1,
+};
+
+/*
+ * The hardware events that we support. We do support cache operations but
+ * we have harvard caches and no way to combine instruction and data
+ * accesses/misses in hardware.
+ */
+static const unsigned armv6_perf_map[PERF_COUNT_HW_MAX] = {
+       [PERF_COUNT_HW_CPU_CYCLES]          = ARMV6_PERFCTR_CPU_CYCLES,
+       [PERF_COUNT_HW_INSTRUCTIONS]        = ARMV6_PERFCTR_INSTR_EXEC,
+       [PERF_COUNT_HW_CACHE_REFERENCES]    = HW_OP_UNSUPPORTED,
+       [PERF_COUNT_HW_CACHE_MISSES]        = HW_OP_UNSUPPORTED,
+       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV6_PERFCTR_BR_EXEC,
+       [PERF_COUNT_HW_BRANCH_MISSES]       = ARMV6_PERFCTR_BR_MISPREDICT,
+       [PERF_COUNT_HW_BUS_CYCLES]          = HW_OP_UNSUPPORTED,
+};
+
+static const unsigned armv6_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
+                                         [PERF_COUNT_HW_CACHE_OP_MAX]
+                                         [PERF_COUNT_HW_CACHE_RESULT_MAX] = {
+       [C(L1D)] = {
+               /*
+                * The performance counters don't differentiate between read
+                * and write accesses/misses so this isn't strictly correct,
+                * but it's the best we can do. Writes and reads get
+                * combined.
+                */
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]      = ARMV6_PERFCTR_DCACHE_ACCESS,
+                       [C(RESULT_MISS)]        = ARMV6_PERFCTR_DCACHE_MISS,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]      = ARMV6_PERFCTR_DCACHE_ACCESS,
+                       [C(RESULT_MISS)]        = ARMV6_PERFCTR_DCACHE_MISS,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
+               },
+       },
+       [C(L1I)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = ARMV6_PERFCTR_ICACHE_MISS,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = ARMV6_PERFCTR_ICACHE_MISS,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
+               },
+       },
+       [C(LL)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
+               },
+       },
+       [C(DTLB)] = {
+               /*
+                * The ARM performance counters can count micro DTLB misses,
+                * micro ITLB misses and main TLB misses. There isn't an event
+                * for TLB misses, so use the micro misses here and if users
+                * want the main TLB misses they can use a raw counter.
+                */
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = ARMV6_PERFCTR_DTLB_MISS,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = ARMV6_PERFCTR_DTLB_MISS,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
+               },
+       },
+       [C(ITLB)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = ARMV6_PERFCTR_ITLB_MISS,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = ARMV6_PERFCTR_ITLB_MISS,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
+               },
+       },
+       [C(BPU)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
+               },
+       },
+};
+
+enum armv6mpcore_perf_types {
+       ARMV6MPCORE_PERFCTR_ICACHE_MISS     = 0x0,
+       ARMV6MPCORE_PERFCTR_IBUF_STALL      = 0x1,
+       ARMV6MPCORE_PERFCTR_DDEP_STALL      = 0x2,
+       ARMV6MPCORE_PERFCTR_ITLB_MISS       = 0x3,
+       ARMV6MPCORE_PERFCTR_DTLB_MISS       = 0x4,
+       ARMV6MPCORE_PERFCTR_BR_EXEC         = 0x5,
+       ARMV6MPCORE_PERFCTR_BR_NOTPREDICT   = 0x6,
+       ARMV6MPCORE_PERFCTR_BR_MISPREDICT   = 0x7,
+       ARMV6MPCORE_PERFCTR_INSTR_EXEC      = 0x8,
+       ARMV6MPCORE_PERFCTR_DCACHE_RDACCESS = 0xA,
+       ARMV6MPCORE_PERFCTR_DCACHE_RDMISS   = 0xB,
+       ARMV6MPCORE_PERFCTR_DCACHE_WRACCESS = 0xC,
+       ARMV6MPCORE_PERFCTR_DCACHE_WRMISS   = 0xD,
+       ARMV6MPCORE_PERFCTR_DCACHE_EVICTION = 0xE,
+       ARMV6MPCORE_PERFCTR_SW_PC_CHANGE    = 0xF,
+       ARMV6MPCORE_PERFCTR_MAIN_TLB_MISS   = 0x10,
+       ARMV6MPCORE_PERFCTR_EXPL_MEM_ACCESS = 0x11,
+       ARMV6MPCORE_PERFCTR_LSU_FULL_STALL  = 0x12,
+       ARMV6MPCORE_PERFCTR_WBUF_DRAINED    = 0x13,
+       ARMV6MPCORE_PERFCTR_CPU_CYCLES      = 0xFF,
+};
+
+/*
+ * The hardware events that we support. We do support cache operations but
+ * we have harvard caches and no way to combine instruction and data
+ * accesses/misses in hardware.
+ */
+static const unsigned armv6mpcore_perf_map[PERF_COUNT_HW_MAX] = {
+       [PERF_COUNT_HW_CPU_CYCLES]          = ARMV6MPCORE_PERFCTR_CPU_CYCLES,
+       [PERF_COUNT_HW_INSTRUCTIONS]        = ARMV6MPCORE_PERFCTR_INSTR_EXEC,
+       [PERF_COUNT_HW_CACHE_REFERENCES]    = HW_OP_UNSUPPORTED,
+       [PERF_COUNT_HW_CACHE_MISSES]        = HW_OP_UNSUPPORTED,
+       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV6MPCORE_PERFCTR_BR_EXEC,
+       [PERF_COUNT_HW_BRANCH_MISSES]       = ARMV6MPCORE_PERFCTR_BR_MISPREDICT,
+       [PERF_COUNT_HW_BUS_CYCLES]          = HW_OP_UNSUPPORTED,
+};
+
+static const unsigned armv6mpcore_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
+                                       [PERF_COUNT_HW_CACHE_OP_MAX]
+                                       [PERF_COUNT_HW_CACHE_RESULT_MAX] = {
+       [C(L1D)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]  =
+                               ARMV6MPCORE_PERFCTR_DCACHE_RDACCESS,
+                       [C(RESULT_MISS)]    =
+                               ARMV6MPCORE_PERFCTR_DCACHE_RDMISS,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]  =
+                               ARMV6MPCORE_PERFCTR_DCACHE_WRACCESS,
+                       [C(RESULT_MISS)]    =
+                               ARMV6MPCORE_PERFCTR_DCACHE_WRMISS,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]  = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]    = CACHE_OP_UNSUPPORTED,
+               },
+       },
+       [C(L1I)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]  = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]    = ARMV6MPCORE_PERFCTR_ICACHE_MISS,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]  = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]    = ARMV6MPCORE_PERFCTR_ICACHE_MISS,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]  = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]    = CACHE_OP_UNSUPPORTED,
+               },
+       },
+       [C(LL)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]  = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]    = CACHE_OP_UNSUPPORTED,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]  = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]    = CACHE_OP_UNSUPPORTED,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]  = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]    = CACHE_OP_UNSUPPORTED,
+               },
+       },
+       [C(DTLB)] = {
+               /*
+                * The ARM performance counters can count micro DTLB misses,
+                * micro ITLB misses and main TLB misses. There isn't an event
+                * for TLB misses, so use the micro misses here and if users
+                * want the main TLB misses they can use a raw counter.
+                */
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]  = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]    = ARMV6MPCORE_PERFCTR_DTLB_MISS,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]  = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]    = ARMV6MPCORE_PERFCTR_DTLB_MISS,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]  = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]    = CACHE_OP_UNSUPPORTED,
+               },
+       },
+       [C(ITLB)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]  = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]    = ARMV6MPCORE_PERFCTR_ITLB_MISS,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]  = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]    = ARMV6MPCORE_PERFCTR_ITLB_MISS,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]  = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]    = CACHE_OP_UNSUPPORTED,
+               },
+       },
+       [C(BPU)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]  = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]    = CACHE_OP_UNSUPPORTED,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]  = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]    = CACHE_OP_UNSUPPORTED,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]  = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]    = CACHE_OP_UNSUPPORTED,
+               },
+       },
+};
+
+static inline unsigned long
+armv6_pmcr_read(void)
+{
+       u32 val;
+       asm volatile("mrc   p15, 0, %0, c15, c12, 0" : "=r"(val));
+       return val;
+}
+
+static inline void
+armv6_pmcr_write(unsigned long val)
+{
+       asm volatile("mcr   p15, 0, %0, c15, c12, 0" : : "r"(val));
+}
+
+#define ARMV6_PMCR_ENABLE              (1 << 0)
+#define ARMV6_PMCR_CTR01_RESET         (1 << 1)
+#define ARMV6_PMCR_CCOUNT_RESET                (1 << 2)
+#define ARMV6_PMCR_CCOUNT_DIV          (1 << 3)
+#define ARMV6_PMCR_COUNT0_IEN          (1 << 4)
+#define ARMV6_PMCR_COUNT1_IEN          (1 << 5)
+#define ARMV6_PMCR_CCOUNT_IEN          (1 << 6)
+#define ARMV6_PMCR_COUNT0_OVERFLOW     (1 << 8)
+#define ARMV6_PMCR_COUNT1_OVERFLOW     (1 << 9)
+#define ARMV6_PMCR_CCOUNT_OVERFLOW     (1 << 10)
+#define ARMV6_PMCR_EVT_COUNT0_SHIFT    20
+#define ARMV6_PMCR_EVT_COUNT0_MASK     (0xFF << ARMV6_PMCR_EVT_COUNT0_SHIFT)
+#define ARMV6_PMCR_EVT_COUNT1_SHIFT    12
+#define ARMV6_PMCR_EVT_COUNT1_MASK     (0xFF << ARMV6_PMCR_EVT_COUNT1_SHIFT)
+
+#define ARMV6_PMCR_OVERFLOWED_MASK \
+       (ARMV6_PMCR_COUNT0_OVERFLOW | ARMV6_PMCR_COUNT1_OVERFLOW | \
+        ARMV6_PMCR_CCOUNT_OVERFLOW)
+
+static inline int
+armv6_pmcr_has_overflowed(unsigned long pmcr)
+{
+       return (pmcr & ARMV6_PMCR_OVERFLOWED_MASK);
+}
+
+static inline int
+armv6_pmcr_counter_has_overflowed(unsigned long pmcr,
+                                 enum armv6_counters counter)
+{
+       int ret = 0;
+
+       if (ARMV6_CYCLE_COUNTER == counter)
+               ret = pmcr & ARMV6_PMCR_CCOUNT_OVERFLOW;
+       else if (ARMV6_COUNTER0 == counter)
+               ret = pmcr & ARMV6_PMCR_COUNT0_OVERFLOW;
+       else if (ARMV6_COUNTER1 == counter)
+               ret = pmcr & ARMV6_PMCR_COUNT1_OVERFLOW;
+       else
+               WARN_ONCE(1, "invalid counter number (%d)\n", counter);
+
+       return ret;
+}
+
+static inline u32
+armv6pmu_read_counter(int counter)
+{
+       unsigned long value = 0;
+
+       if (ARMV6_CYCLE_COUNTER == counter)
+               asm volatile("mrc   p15, 0, %0, c15, c12, 1" : "=r"(value));
+       else if (ARMV6_COUNTER0 == counter)
+               asm volatile("mrc   p15, 0, %0, c15, c12, 2" : "=r"(value));
+       else if (ARMV6_COUNTER1 == counter)
+               asm volatile("mrc   p15, 0, %0, c15, c12, 3" : "=r"(value));
+       else
+               WARN_ONCE(1, "invalid counter number (%d)\n", counter);
+
+       return value;
+}
+
+static inline void
+armv6pmu_write_counter(int counter,
+                      u32 value)
+{
+       if (ARMV6_CYCLE_COUNTER == counter)
+               asm volatile("mcr   p15, 0, %0, c15, c12, 1" : : "r"(value));
+       else if (ARMV6_COUNTER0 == counter)
+               asm volatile("mcr   p15, 0, %0, c15, c12, 2" : : "r"(value));
+       else if (ARMV6_COUNTER1 == counter)
+               asm volatile("mcr   p15, 0, %0, c15, c12, 3" : : "r"(value));
+       else
+               WARN_ONCE(1, "invalid counter number (%d)\n", counter);
+}
+
+void
+armv6pmu_enable_event(struct hw_perf_event *hwc,
+                     int idx)
+{
+       unsigned long val, mask, evt, flags;
+
+       if (ARMV6_CYCLE_COUNTER == idx) {
+               mask    = 0;
+               evt     = ARMV6_PMCR_CCOUNT_IEN;
+       } else if (ARMV6_COUNTER0 == idx) {
+               mask    = ARMV6_PMCR_EVT_COUNT0_MASK;
+               evt     = (hwc->config_base << ARMV6_PMCR_EVT_COUNT0_SHIFT) |
+                         ARMV6_PMCR_COUNT0_IEN;
+       } else if (ARMV6_COUNTER1 == idx) {
+               mask    = ARMV6_PMCR_EVT_COUNT1_MASK;
+               evt     = (hwc->config_base << ARMV6_PMCR_EVT_COUNT1_SHIFT) |
+                         ARMV6_PMCR_COUNT1_IEN;
+       } else {
+               WARN_ONCE(1, "invalid counter number (%d)\n", idx);
+               return;
+       }
+
+       /*
+        * Mask out the current event and set the counter to count the event
+        * that we're interested in.
+        */
+       spin_lock_irqsave(&pmu_lock, flags);
+       val = armv6_pmcr_read();
+       val &= ~mask;
+       val |= evt;
+       armv6_pmcr_write(val);
+       spin_unlock_irqrestore(&pmu_lock, flags);
+}
+
+static irqreturn_t
+armv6pmu_handle_irq(int irq_num,
+                   void *dev)
+{
+       unsigned long pmcr = armv6_pmcr_read();
+       struct perf_sample_data data;
+       struct cpu_hw_events *cpuc;
+       struct pt_regs *regs;
+       int idx;
+
+       if (!armv6_pmcr_has_overflowed(pmcr))
+               return IRQ_NONE;
+
+       regs = get_irq_regs();
+
+       /*
+        * The interrupts are cleared by writing the overflow flags back to
+        * the control register. All of the other bits don't have any effect
+        * if they are rewritten, so write the whole value back.
+        */
+       armv6_pmcr_write(pmcr);
+
+       data.addr = 0;
+
+       cpuc = &__get_cpu_var(cpu_hw_events);
+       for (idx = 0; idx <= armpmu->num_events; ++idx) {
+               struct perf_event *event = cpuc->events[idx];
+               struct hw_perf_event *hwc;
+
+               if (!test_bit(idx, cpuc->active_mask))
+                       continue;
+
+               /*
+                * We have a single interrupt for all counters. Check that
+                * each counter has overflowed before we process it.
+                */
+               if (!armv6_pmcr_counter_has_overflowed(pmcr, idx))
+                       continue;
+
+               hwc = &event->hw;
+               armpmu_event_update(event, hwc, idx);
+               data.period = event->hw.last_period;
+               if (!armpmu_event_set_period(event, hwc, idx))
+                       continue;
+
+               if (perf_event_overflow(event, 0, &data, regs))
+                       armpmu->disable(hwc, idx);
+       }
+
+       /*
+        * Handle the pending perf events.
+        *
+        * Note: this call *must* be run with interrupts enabled. For
+        * platforms that can have the PMU interrupts raised as a PMI, this
+        * will not work.
+        */
+       perf_event_do_pending();
+
+       return IRQ_HANDLED;
+}
+
+static void
+armv6pmu_start(void)
+{
+       unsigned long flags, val;
+
+       spin_lock_irqsave(&pmu_lock, flags);
+       val = armv6_pmcr_read();
+       val |= ARMV6_PMCR_ENABLE;
+       armv6_pmcr_write(val);
+       spin_unlock_irqrestore(&pmu_lock, flags);
+}
+
+void
+armv6pmu_stop(void)
+{
+       unsigned long flags, val;
+
+       spin_lock_irqsave(&pmu_lock, flags);
+       val = armv6_pmcr_read();
+       val &= ~ARMV6_PMCR_ENABLE;
+       armv6_pmcr_write(val);
+       spin_unlock_irqrestore(&pmu_lock, flags);
+}
+
+static inline int
+armv6pmu_event_map(int config)
+{
+       int mapping = armv6_perf_map[config];
+       if (HW_OP_UNSUPPORTED == mapping)
+               mapping = -EOPNOTSUPP;
+       return mapping;
+}
+
+static inline int
+armv6mpcore_pmu_event_map(int config)
+{
+       int mapping = armv6mpcore_perf_map[config];
+       if (HW_OP_UNSUPPORTED == mapping)
+               mapping = -EOPNOTSUPP;
+       return mapping;
+}
+
+static u64
+armv6pmu_raw_event(u64 config)
+{
+       return config & 0xff;
+}
+
+static int
+armv6pmu_get_event_idx(struct cpu_hw_events *cpuc,
+                      struct hw_perf_event *event)
+{
+       /* Always place a cycle counter into the cycle counter. */
+       if (ARMV6_PERFCTR_CPU_CYCLES == event->config_base) {
+               if (test_and_set_bit(ARMV6_CYCLE_COUNTER, cpuc->used_mask))
+                       return -EAGAIN;
+
+               return ARMV6_CYCLE_COUNTER;
+       } else {
+               /*
+                * For anything other than a cycle counter, try and use
+                * counter0 and counter1.
+                */
+               if (!test_and_set_bit(ARMV6_COUNTER1, cpuc->used_mask)) {
+                       return ARMV6_COUNTER1;
+               }
+
+               if (!test_and_set_bit(ARMV6_COUNTER0, cpuc->used_mask)) {
+                       return ARMV6_COUNTER0;
+               }
+
+               /* The counters are all in use. */
+               return -EAGAIN;
+       }
+}
+
+static void
+armv6pmu_disable_event(struct hw_perf_event *hwc,
+                      int idx)
+{
+       unsigned long val, mask, evt, flags;
+
+       if (ARMV6_CYCLE_COUNTER == idx) {
+               mask    = ARMV6_PMCR_CCOUNT_IEN;
+               evt     = 0;
+       } else if (ARMV6_COUNTER0 == idx) {
+               mask    = ARMV6_PMCR_COUNT0_IEN | ARMV6_PMCR_EVT_COUNT0_MASK;
+               evt     = ARMV6_PERFCTR_NOP << ARMV6_PMCR_EVT_COUNT0_SHIFT;
+       } else if (ARMV6_COUNTER1 == idx) {
+               mask    = ARMV6_PMCR_COUNT1_IEN | ARMV6_PMCR_EVT_COUNT1_MASK;
+               evt     = ARMV6_PERFCTR_NOP << ARMV6_PMCR_EVT_COUNT1_SHIFT;
+       } else {
+               WARN_ONCE(1, "invalid counter number (%d)\n", idx);
+               return;
+       }
+
+       /*
+        * Mask out the current event and set the counter to count the number
+        * of ETM bus signal assertion cycles. The external reporting should
+        * be disabled and so this should never increment.
+        */
+       spin_lock_irqsave(&pmu_lock, flags);
+       val = armv6_pmcr_read();
+       val &= ~mask;
+       val |= evt;
+       armv6_pmcr_write(val);
+       spin_unlock_irqrestore(&pmu_lock, flags);
+}
+
+static void
+armv6mpcore_pmu_disable_event(struct hw_perf_event *hwc,
+                             int idx)
+{
+       unsigned long val, mask, flags, evt = 0;
+
+       if (ARMV6_CYCLE_COUNTER == idx) {
+               mask    = ARMV6_PMCR_CCOUNT_IEN;
+       } else if (ARMV6_COUNTER0 == idx) {
+               mask    = ARMV6_PMCR_COUNT0_IEN;
+       } else if (ARMV6_COUNTER1 == idx) {
+               mask    = ARMV6_PMCR_COUNT1_IEN;
+       } else {
+               WARN_ONCE(1, "invalid counter number (%d)\n", idx);
+               return;
+       }
+
+       /*
+        * Unlike UP ARMv6, we don't have a way of stopping the counters. We
+        * simply disable the interrupt reporting.
+        */
+       spin_lock_irqsave(&pmu_lock, flags);
+       val = armv6_pmcr_read();
+       val &= ~mask;
+       val |= evt;
+       armv6_pmcr_write(val);
+       spin_unlock_irqrestore(&pmu_lock, flags);
+}
+
+static const struct arm_pmu armv6pmu = {
+       .name                   = "v6",
+       .handle_irq             = armv6pmu_handle_irq,
+       .enable                 = armv6pmu_enable_event,
+       .disable                = armv6pmu_disable_event,
+       .event_map              = armv6pmu_event_map,
+       .raw_event              = armv6pmu_raw_event,
+       .read_counter           = armv6pmu_read_counter,
+       .write_counter          = armv6pmu_write_counter,
+       .get_event_idx          = armv6pmu_get_event_idx,
+       .start                  = armv6pmu_start,
+       .stop                   = armv6pmu_stop,
+       .num_events             = 3,
+       .max_period             = (1LLU << 32) - 1,
+};
+
+/*
+ * ARMv6mpcore is almost identical to single core ARMv6 with the exception
+ * that some of the events have different enumerations and that there is no
+ * *hack* to stop the programmable counters. To stop the counters we simply
+ * disable the interrupt reporting and update the event. When unthrottling we
+ * reset the period and enable the interrupt reporting.
+ */
+static const struct arm_pmu armv6mpcore_pmu = {
+       .name                   = "v6mpcore",
+       .handle_irq             = armv6pmu_handle_irq,
+       .enable                 = armv6pmu_enable_event,
+       .disable                = armv6mpcore_pmu_disable_event,
+       .event_map              = armv6mpcore_pmu_event_map,
+       .raw_event              = armv6pmu_raw_event,
+       .read_counter           = armv6pmu_read_counter,
+       .write_counter          = armv6pmu_write_counter,
+       .get_event_idx          = armv6pmu_get_event_idx,
+       .start                  = armv6pmu_start,
+       .stop                   = armv6pmu_stop,
+       .num_events             = 3,
+       .max_period             = (1LLU << 32) - 1,
+};
+
+/*
+ * ARMv7 Cortex-A8 and Cortex-A9 Performance Events handling code.
+ *
+ * Copied from ARMv6 code, with the low level code inspired
+ *  by the ARMv7 Oprofile code.
+ *
+ * Cortex-A8 has up to 4 configurable performance counters and
+ *  a single cycle counter.
+ * Cortex-A9 has up to 31 configurable performance counters and
+ *  a single cycle counter.
+ *
+ * All counters can be enabled/disabled and IRQ masked separately. The cycle
+ *  counter and all 4 performance counters together can be reset separately.
+ */
+
+#define ARMV7_PMU_CORTEX_A8_NAME               "ARMv7 Cortex-A8"
+
+#define ARMV7_PMU_CORTEX_A9_NAME               "ARMv7 Cortex-A9"
+
+/* Common ARMv7 event types */
+enum armv7_perf_types {
+       ARMV7_PERFCTR_PMNC_SW_INCR              = 0x00,
+       ARMV7_PERFCTR_IFETCH_MISS               = 0x01,
+       ARMV7_PERFCTR_ITLB_MISS                 = 0x02,
+       ARMV7_PERFCTR_DCACHE_REFILL             = 0x03,
+       ARMV7_PERFCTR_DCACHE_ACCESS             = 0x04,
+       ARMV7_PERFCTR_DTLB_REFILL               = 0x05,
+       ARMV7_PERFCTR_DREAD                     = 0x06,
+       ARMV7_PERFCTR_DWRITE                    = 0x07,
+
+       ARMV7_PERFCTR_EXC_TAKEN                 = 0x09,
+       ARMV7_PERFCTR_EXC_EXECUTED              = 0x0A,
+       ARMV7_PERFCTR_CID_WRITE                 = 0x0B,
+       /* ARMV7_PERFCTR_PC_WRITE is equivalent to HW_BRANCH_INSTRUCTIONS.
+        * It counts:
+        *  - all branch instructions,
+        *  - instructions that explicitly write the PC,
+        *  - exception generating instructions.
+        */
+       ARMV7_PERFCTR_PC_WRITE                  = 0x0C,
+       ARMV7_PERFCTR_PC_IMM_BRANCH             = 0x0D,
+       ARMV7_PERFCTR_UNALIGNED_ACCESS          = 0x0F,
+       ARMV7_PERFCTR_PC_BRANCH_MIS_PRED        = 0x10,
+       ARMV7_PERFCTR_CLOCK_CYCLES              = 0x11,
+
+       ARMV7_PERFCTR_PC_BRANCH_MIS_USED        = 0x12,
+
+       ARMV7_PERFCTR_CPU_CYCLES                = 0xFF
+};
+
+/* ARMv7 Cortex-A8 specific event types */
+enum armv7_a8_perf_types {
+       ARMV7_PERFCTR_INSTR_EXECUTED            = 0x08,
+
+       ARMV7_PERFCTR_PC_PROC_RETURN            = 0x0E,
+
+       ARMV7_PERFCTR_WRITE_BUFFER_FULL         = 0x40,
+       ARMV7_PERFCTR_L2_STORE_MERGED           = 0x41,
+       ARMV7_PERFCTR_L2_STORE_BUFF             = 0x42,
+       ARMV7_PERFCTR_L2_ACCESS                 = 0x43,
+       ARMV7_PERFCTR_L2_CACH_MISS              = 0x44,
+       ARMV7_PERFCTR_AXI_READ_CYCLES           = 0x45,
+       ARMV7_PERFCTR_AXI_WRITE_CYCLES          = 0x46,
+       ARMV7_PERFCTR_MEMORY_REPLAY             = 0x47,
+       ARMV7_PERFCTR_UNALIGNED_ACCESS_REPLAY   = 0x48,
+       ARMV7_PERFCTR_L1_DATA_MISS              = 0x49,
+       ARMV7_PERFCTR_L1_INST_MISS              = 0x4A,
+       ARMV7_PERFCTR_L1_DATA_COLORING          = 0x4B,
+       ARMV7_PERFCTR_L1_NEON_DATA              = 0x4C,
+       ARMV7_PERFCTR_L1_NEON_CACH_DATA         = 0x4D,
+       ARMV7_PERFCTR_L2_NEON                   = 0x4E,
+       ARMV7_PERFCTR_L2_NEON_HIT               = 0x4F,
+       ARMV7_PERFCTR_L1_INST                   = 0x50,
+       ARMV7_PERFCTR_PC_RETURN_MIS_PRED        = 0x51,
+       ARMV7_PERFCTR_PC_BRANCH_FAILED          = 0x52,
+       ARMV7_PERFCTR_PC_BRANCH_TAKEN           = 0x53,
+       ARMV7_PERFCTR_PC_BRANCH_EXECUTED        = 0x54,
+       ARMV7_PERFCTR_OP_EXECUTED               = 0x55,
+       ARMV7_PERFCTR_CYCLES_INST_STALL         = 0x56,
+       ARMV7_PERFCTR_CYCLES_INST               = 0x57,
+       ARMV7_PERFCTR_CYCLES_NEON_DATA_STALL    = 0x58,
+       ARMV7_PERFCTR_CYCLES_NEON_INST_STALL    = 0x59,
+       ARMV7_PERFCTR_NEON_CYCLES               = 0x5A,
+
+       ARMV7_PERFCTR_PMU0_EVENTS               = 0x70,
+       ARMV7_PERFCTR_PMU1_EVENTS               = 0x71,
+       ARMV7_PERFCTR_PMU_EVENTS                = 0x72,
+};
+
+/* ARMv7 Cortex-A9 specific event types */
+enum armv7_a9_perf_types {
+       ARMV7_PERFCTR_JAVA_HW_BYTECODE_EXEC     = 0x40,
+       ARMV7_PERFCTR_JAVA_SW_BYTECODE_EXEC     = 0x41,
+       ARMV7_PERFCTR_JAZELLE_BRANCH_EXEC       = 0x42,
+
+       ARMV7_PERFCTR_COHERENT_LINE_MISS        = 0x50,
+       ARMV7_PERFCTR_COHERENT_LINE_HIT         = 0x51,
+
+       ARMV7_PERFCTR_ICACHE_DEP_STALL_CYCLES   = 0x60,
+       ARMV7_PERFCTR_DCACHE_DEP_STALL_CYCLES   = 0x61,
+       ARMV7_PERFCTR_TLB_MISS_DEP_STALL_CYCLES = 0x62,
+       ARMV7_PERFCTR_STREX_EXECUTED_PASSED     = 0x63,
+       ARMV7_PERFCTR_STREX_EXECUTED_FAILED     = 0x64,
+       ARMV7_PERFCTR_DATA_EVICTION             = 0x65,
+       ARMV7_PERFCTR_ISSUE_STAGE_NO_INST       = 0x66,
+       ARMV7_PERFCTR_ISSUE_STAGE_EMPTY         = 0x67,
+       ARMV7_PERFCTR_INST_OUT_OF_RENAME_STAGE  = 0x68,
+
+       ARMV7_PERFCTR_PREDICTABLE_FUNCT_RETURNS = 0x6E,
+
+       ARMV7_PERFCTR_MAIN_UNIT_EXECUTED_INST   = 0x70,
+       ARMV7_PERFCTR_SECOND_UNIT_EXECUTED_INST = 0x71,
+       ARMV7_PERFCTR_LD_ST_UNIT_EXECUTED_INST  = 0x72,
+       ARMV7_PERFCTR_FP_EXECUTED_INST          = 0x73,
+       ARMV7_PERFCTR_NEON_EXECUTED_INST        = 0x74,
+
+       ARMV7_PERFCTR_PLD_FULL_DEP_STALL_CYCLES = 0x80,
+       ARMV7_PERFCTR_DATA_WR_DEP_STALL_CYCLES  = 0x81,
+       ARMV7_PERFCTR_ITLB_MISS_DEP_STALL_CYCLES        = 0x82,
+       ARMV7_PERFCTR_DTLB_MISS_DEP_STALL_CYCLES        = 0x83,
+       ARMV7_PERFCTR_MICRO_ITLB_MISS_DEP_STALL_CYCLES  = 0x84,
+       ARMV7_PERFCTR_MICRO_DTLB_MISS_DEP_STALL_CYCLES  = 0x85,
+       ARMV7_PERFCTR_DMB_DEP_STALL_CYCLES      = 0x86,
+
+       ARMV7_PERFCTR_INTGR_CLK_ENABLED_CYCLES  = 0x8A,
+       ARMV7_PERFCTR_DATA_ENGINE_CLK_EN_CYCLES = 0x8B,
+
+       ARMV7_PERFCTR_ISB_INST                  = 0x90,
+       ARMV7_PERFCTR_DSB_INST                  = 0x91,
+       ARMV7_PERFCTR_DMB_INST                  = 0x92,
+       ARMV7_PERFCTR_EXT_INTERRUPTS            = 0x93,
+
+       ARMV7_PERFCTR_PLE_CACHE_LINE_RQST_COMPLETED     = 0xA0,
+       ARMV7_PERFCTR_PLE_CACHE_LINE_RQST_SKIPPED       = 0xA1,
+       ARMV7_PERFCTR_PLE_FIFO_FLUSH            = 0xA2,
+       ARMV7_PERFCTR_PLE_RQST_COMPLETED        = 0xA3,
+       ARMV7_PERFCTR_PLE_FIFO_OVERFLOW         = 0xA4,
+       ARMV7_PERFCTR_PLE_RQST_PROG             = 0xA5
+};
+
+/*
+ * Cortex-A8 HW events mapping
+ *
+ * The hardware events that we support. We do support cache operations but
+ * we have harvard caches and no way to combine instruction and data
+ * accesses/misses in hardware.
+ */
+static const unsigned armv7_a8_perf_map[PERF_COUNT_HW_MAX] = {
+       [PERF_COUNT_HW_CPU_CYCLES]          = ARMV7_PERFCTR_CPU_CYCLES,
+       [PERF_COUNT_HW_INSTRUCTIONS]        = ARMV7_PERFCTR_INSTR_EXECUTED,
+       [PERF_COUNT_HW_CACHE_REFERENCES]    = HW_OP_UNSUPPORTED,
+       [PERF_COUNT_HW_CACHE_MISSES]        = HW_OP_UNSUPPORTED,
+       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_PERFCTR_PC_WRITE,
+       [PERF_COUNT_HW_BRANCH_MISSES]       = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
+       [PERF_COUNT_HW_BUS_CYCLES]          = ARMV7_PERFCTR_CLOCK_CYCLES,
+};
+
+static const unsigned armv7_a8_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
+                                         [PERF_COUNT_HW_CACHE_OP_MAX]
+                                         [PERF_COUNT_HW_CACHE_RESULT_MAX] = {
+       [C(L1D)] = {
+               /*
+                * The performance counters don't differentiate between read
+                * and write accesses/misses so this isn't strictly correct,
+                * but it's the best we can do. Writes and reads get
+                * combined.
+                */
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]      = ARMV7_PERFCTR_DCACHE_ACCESS,
+                       [C(RESULT_MISS)]        = ARMV7_PERFCTR_DCACHE_REFILL,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]      = ARMV7_PERFCTR_DCACHE_ACCESS,
+                       [C(RESULT_MISS)]        = ARMV7_PERFCTR_DCACHE_REFILL,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
+               },
+       },
+       [C(L1I)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]      = ARMV7_PERFCTR_L1_INST,
+                       [C(RESULT_MISS)]        = ARMV7_PERFCTR_L1_INST_MISS,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]      = ARMV7_PERFCTR_L1_INST,
+                       [C(RESULT_MISS)]        = ARMV7_PERFCTR_L1_INST_MISS,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
+               },
+       },
+       [C(LL)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]      = ARMV7_PERFCTR_L2_ACCESS,
+                       [C(RESULT_MISS)]        = ARMV7_PERFCTR_L2_CACH_MISS,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]      = ARMV7_PERFCTR_L2_ACCESS,
+                       [C(RESULT_MISS)]        = ARMV7_PERFCTR_L2_CACH_MISS,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
+               },
+       },
+       [C(DTLB)] = {
+               /*
+                * Only ITLB misses and DTLB refills are supported.
+                * If users want the DTLB refills misses a raw counter
+                * must be used.
+                */
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = ARMV7_PERFCTR_DTLB_REFILL,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = ARMV7_PERFCTR_DTLB_REFILL,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
+               },
+       },
+       [C(ITLB)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = ARMV7_PERFCTR_ITLB_MISS,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = ARMV7_PERFCTR_ITLB_MISS,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
+               },
+       },
+       [C(BPU)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]      = ARMV7_PERFCTR_PC_WRITE,
+                       [C(RESULT_MISS)]
+                                       = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]      = ARMV7_PERFCTR_PC_WRITE,
+                       [C(RESULT_MISS)]
+                                       = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
+               },
+       },
+};
+
+/*
+ * Cortex-A9 HW events mapping
+ */
+static const unsigned armv7_a9_perf_map[PERF_COUNT_HW_MAX] = {
+       [PERF_COUNT_HW_CPU_CYCLES]          = ARMV7_PERFCTR_CPU_CYCLES,
+       [PERF_COUNT_HW_INSTRUCTIONS]        =
+                                       ARMV7_PERFCTR_INST_OUT_OF_RENAME_STAGE,
+       [PERF_COUNT_HW_CACHE_REFERENCES]    = ARMV7_PERFCTR_COHERENT_LINE_HIT,
+       [PERF_COUNT_HW_CACHE_MISSES]        = ARMV7_PERFCTR_COHERENT_LINE_MISS,
+       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_PERFCTR_PC_WRITE,
+       [PERF_COUNT_HW_BRANCH_MISSES]       = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
+       [PERF_COUNT_HW_BUS_CYCLES]          = ARMV7_PERFCTR_CLOCK_CYCLES,
+};
+
+static const unsigned armv7_a9_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
+                                         [PERF_COUNT_HW_CACHE_OP_MAX]
+                                         [PERF_COUNT_HW_CACHE_RESULT_MAX] = {
+       [C(L1D)] = {
+               /*
+                * The performance counters don't differentiate between read
+                * and write accesses/misses so this isn't strictly correct,
+                * but it's the best we can do. Writes and reads get
+                * combined.
+                */
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]      = ARMV7_PERFCTR_DCACHE_ACCESS,
+                       [C(RESULT_MISS)]        = ARMV7_PERFCTR_DCACHE_REFILL,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]      = ARMV7_PERFCTR_DCACHE_ACCESS,
+                       [C(RESULT_MISS)]        = ARMV7_PERFCTR_DCACHE_REFILL,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
+               },
+       },
+       [C(L1I)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = ARMV7_PERFCTR_IFETCH_MISS,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = ARMV7_PERFCTR_IFETCH_MISS,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
+               },
+       },
+       [C(LL)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
+               },
+       },
+       [C(DTLB)] = {
+               /*
+                * Only ITLB misses and DTLB refills are supported.
+                * If users want the DTLB refills misses a raw counter
+                * must be used.
+                */
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = ARMV7_PERFCTR_DTLB_REFILL,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = ARMV7_PERFCTR_DTLB_REFILL,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
+               },
+       },
+       [C(ITLB)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = ARMV7_PERFCTR_ITLB_MISS,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = ARMV7_PERFCTR_ITLB_MISS,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
+               },
+       },
+       [C(BPU)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]      = ARMV7_PERFCTR_PC_WRITE,
+                       [C(RESULT_MISS)]
+                                       = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]      = ARMV7_PERFCTR_PC_WRITE,
+                       [C(RESULT_MISS)]
+                                       = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
+               },
+       },
+};
+
+/*
+ * Perf Events counters
+ */
+enum armv7_counters {
+       ARMV7_CYCLE_COUNTER             = 1,    /* Cycle counter */
+       ARMV7_COUNTER0                  = 2,    /* First event counter */
+};
+
+/*
+ * The cycle counter is ARMV7_CYCLE_COUNTER.
+ * The first event counter is ARMV7_COUNTER0.
+ * The last event counter is (ARMV7_COUNTER0 + armpmu->num_events - 1).
+ */
+#define        ARMV7_COUNTER_LAST      (ARMV7_COUNTER0 + armpmu->num_events - 1)
+
+/*
+ * ARMv7 low level PMNC access
+ */
+
+/*
+ * Per-CPU PMNC: config reg
+ */
+#define ARMV7_PMNC_E           (1 << 0) /* Enable all counters */
+#define ARMV7_PMNC_P           (1 << 1) /* Reset all counters */
+#define ARMV7_PMNC_C           (1 << 2) /* Cycle counter reset */
+#define ARMV7_PMNC_D           (1 << 3) /* CCNT counts every 64th cpu cycle */
+#define ARMV7_PMNC_X           (1 << 4) /* Export to ETM */
+#define ARMV7_PMNC_DP          (1 << 5) /* Disable CCNT if non-invasive debug*/
+#define        ARMV7_PMNC_N_SHIFT      11       /* Number of counters supported */
+#define        ARMV7_PMNC_N_MASK       0x1f
+#define        ARMV7_PMNC_MASK         0x3f     /* Mask for writable bits */
+
+/*
+ * Available counters
+ */
+#define ARMV7_CNT0             0       /* First event counter */
+#define ARMV7_CCNT             31      /* Cycle counter */
+
+/* Perf Event to low level counters mapping */
+#define ARMV7_EVENT_CNT_TO_CNTx        (ARMV7_COUNTER0 - ARMV7_CNT0)
+
+/*
+ * CNTENS: counters enable reg
+ */
+#define ARMV7_CNTENS_P(idx)    (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx))
+#define ARMV7_CNTENS_C         (1 << ARMV7_CCNT)
+
+/*
+ * CNTENC: counters disable reg
+ */
+#define ARMV7_CNTENC_P(idx)    (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx))
+#define ARMV7_CNTENC_C         (1 << ARMV7_CCNT)
+
+/*
+ * INTENS: counters overflow interrupt enable reg
+ */
+#define ARMV7_INTENS_P(idx)    (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx))
+#define ARMV7_INTENS_C         (1 << ARMV7_CCNT)
+
+/*
+ * INTENC: counters overflow interrupt disable reg
+ */
+#define ARMV7_INTENC_P(idx)    (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx))
+#define ARMV7_INTENC_C         (1 << ARMV7_CCNT)
+
+/*
+ * EVTSEL: Event selection reg
+ */
+#define        ARMV7_EVTSEL_MASK       0x7f            /* Mask for writable bits */
+
+/*
+ * SELECT: Counter selection reg
+ */
+#define        ARMV7_SELECT_MASK       0x1f            /* Mask for writable bits */
+
+/*
+ * FLAG: counters overflow flag status reg
+ */
+#define ARMV7_FLAG_P(idx)      (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx))
+#define ARMV7_FLAG_C           (1 << ARMV7_CCNT)
+#define        ARMV7_FLAG_MASK         0xffffffff      /* Mask for writable bits */
+#define        ARMV7_OVERFLOWED_MASK   ARMV7_FLAG_MASK
+
+static inline unsigned long armv7_pmnc_read(void)
+{
+       u32 val;
+       asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r"(val));
+       return val;
+}
+
+static inline void armv7_pmnc_write(unsigned long val)
+{
+       val &= ARMV7_PMNC_MASK;
+       asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r"(val));
+}
+
+static inline int armv7_pmnc_has_overflowed(unsigned long pmnc)
+{
+       return pmnc & ARMV7_OVERFLOWED_MASK;
+}
+
+static inline int armv7_pmnc_counter_has_overflowed(unsigned long pmnc,
+                                       enum armv7_counters counter)
+{
+       int ret;
+
+       if (counter == ARMV7_CYCLE_COUNTER)
+               ret = pmnc & ARMV7_FLAG_C;
+       else if ((counter >= ARMV7_COUNTER0) && (counter <= ARMV7_COUNTER_LAST))
+               ret = pmnc & ARMV7_FLAG_P(counter);
+       else
+               pr_err("CPU%u checking wrong counter %d overflow status\n",
+                       smp_processor_id(), counter);
+
+       return ret;
+}
+
+static inline int armv7_pmnc_select_counter(unsigned int idx)
+{
+       u32 val;
+
+       if ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST)) {
+               pr_err("CPU%u selecting wrong PMNC counter"
+                       " %d\n", smp_processor_id(), idx);
+               return -1;
+       }
+
+       val = (idx - ARMV7_EVENT_CNT_TO_CNTx) & ARMV7_SELECT_MASK;
+       asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val));
+
+       return idx;
+}
+
+static inline u32 armv7pmu_read_counter(int idx)
+{
+       unsigned long value = 0;
+
+       if (idx == ARMV7_CYCLE_COUNTER)
+               asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (value));
+       else if ((idx >= ARMV7_COUNTER0) && (idx <= ARMV7_COUNTER_LAST)) {
+               if (armv7_pmnc_select_counter(idx) == idx)
+                       asm volatile("mrc p15, 0, %0, c9, c13, 2"
+                                    : "=r" (value));
+       } else
+               pr_err("CPU%u reading wrong counter %d\n",
+                       smp_processor_id(), idx);
+
+       return value;
+}
+
+static inline void armv7pmu_write_counter(int idx, u32 value)
+{
+       if (idx == ARMV7_CYCLE_COUNTER)
+               asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (value));
+       else if ((idx >= ARMV7_COUNTER0) && (idx <= ARMV7_COUNTER_LAST)) {
+               if (armv7_pmnc_select_counter(idx) == idx)
+                       asm volatile("mcr p15, 0, %0, c9, c13, 2"
+                                    : : "r" (value));
+       } else
+               pr_err("CPU%u writing wrong counter %d\n",
+                       smp_processor_id(), idx);
+}
+
+static inline void armv7_pmnc_write_evtsel(unsigned int idx, u32 val)
+{
+       if (armv7_pmnc_select_counter(idx) == idx) {
+               val &= ARMV7_EVTSEL_MASK;
+               asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val));
+       }
+}
+
+static inline u32 armv7_pmnc_enable_counter(unsigned int idx)
+{
+       u32 val;
+
+       if ((idx != ARMV7_CYCLE_COUNTER) &&
+           ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST))) {
+               pr_err("CPU%u enabling wrong PMNC counter"
+                       " %d\n", smp_processor_id(), idx);
+               return -1;
+       }
+
+       if (idx == ARMV7_CYCLE_COUNTER)
+               val = ARMV7_CNTENS_C;
+       else
+               val = ARMV7_CNTENS_P(idx);
+
+       asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val));
+
+       return idx;
+}
+
+static inline u32 armv7_pmnc_disable_counter(unsigned int idx)
+{
+       u32 val;
+
+
+       if ((idx != ARMV7_CYCLE_COUNTER) &&
+           ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST))) {
+               pr_err("CPU%u disabling wrong PMNC counter"
+                       " %d\n", smp_processor_id(), idx);
+               return -1;
+       }
+
+       if (idx == ARMV7_CYCLE_COUNTER)
+               val = ARMV7_CNTENC_C;
+       else
+               val = ARMV7_CNTENC_P(idx);
+
+       asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val));
+
+       return idx;
+}
+
+static inline u32 armv7_pmnc_enable_intens(unsigned int idx)
+{
+       u32 val;
+
+       if ((idx != ARMV7_CYCLE_COUNTER) &&
+           ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST))) {
+               pr_err("CPU%u enabling wrong PMNC counter"
+                       " interrupt enable %d\n", smp_processor_id(), idx);
+               return -1;
+       }
+
+       if (idx == ARMV7_CYCLE_COUNTER)
+               val = ARMV7_INTENS_C;
+       else
+               val = ARMV7_INTENS_P(idx);
+
+       asm volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (val));
+
+       return idx;
+}
+
+static inline u32 armv7_pmnc_disable_intens(unsigned int idx)
+{
+       u32 val;
+
+       if ((idx != ARMV7_CYCLE_COUNTER) &&
+           ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST))) {
+               pr_err("CPU%u disabling wrong PMNC counter"
+                       " interrupt enable %d\n", smp_processor_id(), idx);
+               return -1;
+       }
+
+       if (idx == ARMV7_CYCLE_COUNTER)
+               val = ARMV7_INTENC_C;
+       else
+               val = ARMV7_INTENC_P(idx);
+
+       asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (val));
+
+       return idx;
+}
+
+static inline u32 armv7_pmnc_getreset_flags(void)
+{
+       u32 val;
+
+       /* Read */
+       asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (val));
+
+       /* Write to clear flags */
+       val &= ARMV7_FLAG_MASK;
+       asm volatile("mcr p15, 0, %0, c9, c12, 3" : : "r" (val));
+
+       return val;
+}
+
+#ifdef DEBUG
+static void armv7_pmnc_dump_regs(void)
+{
+       u32 val;
+       unsigned int cnt;
+
+       printk(KERN_INFO "PMNC registers dump:\n");
+
+       asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val));
+       printk(KERN_INFO "PMNC  =0x%08x\n", val);
+
+       asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r" (val));
+       printk(KERN_INFO "CNTENS=0x%08x\n", val);
+
+       asm volatile("mrc p15, 0, %0, c9, c14, 1" : "=r" (val));
+       printk(KERN_INFO "INTENS=0x%08x\n", val);
+
+       asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (val));
+       printk(KERN_INFO "FLAGS =0x%08x\n", val);
+
+       asm volatile("mrc p15, 0, %0, c9, c12, 5" : "=r" (val));
+       printk(KERN_INFO "SELECT=0x%08x\n", val);
+
+       asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val));
+       printk(KERN_INFO "CCNT  =0x%08x\n", val);
+
+       for (cnt = ARMV7_COUNTER0; cnt < ARMV7_COUNTER_LAST; cnt++) {
+               armv7_pmnc_select_counter(cnt);
+               asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val));
+               printk(KERN_INFO "CNT[%d] count =0x%08x\n",
+                       cnt-ARMV7_EVENT_CNT_TO_CNTx, val);
+               asm volatile("mrc p15, 0, %0, c9, c13, 1" : "=r" (val));
+               printk(KERN_INFO "CNT[%d] evtsel=0x%08x\n",
+                       cnt-ARMV7_EVENT_CNT_TO_CNTx, val);
+       }
+}
+#endif
+
+void armv7pmu_enable_event(struct hw_perf_event *hwc, int idx)
+{
+       unsigned long flags;
+
+       /*
+        * Enable counter and interrupt, and set the counter to count
+        * the event that we're interested in.
+        */
+       spin_lock_irqsave(&pmu_lock, flags);
+
+       /*
+        * Disable counter
+        */
+       armv7_pmnc_disable_counter(idx);
+
+       /*
+        * Set event (if destined for PMNx counters)
+        * We don't need to set the event if it's a cycle count
+        */
+       if (idx != ARMV7_CYCLE_COUNTER)
+               armv7_pmnc_write_evtsel(idx, hwc->config_base);
+
+       /*
+        * Enable interrupt for this counter
+        */
+       armv7_pmnc_enable_intens(idx);
+
+       /*
+        * Enable counter
+        */
+       armv7_pmnc_enable_counter(idx);
+
+       spin_unlock_irqrestore(&pmu_lock, flags);
+}
+
+static void armv7pmu_disable_event(struct hw_perf_event *hwc, int idx)
+{
+       unsigned long flags;
+
+       /*
+        * Disable counter and interrupt
+        */
+       spin_lock_irqsave(&pmu_lock, flags);
+
+       /*
+        * Disable counter
+        */
+       armv7_pmnc_disable_counter(idx);
+
+       /*
+        * Disable interrupt for this counter
+        */
+       armv7_pmnc_disable_intens(idx);
+
+       spin_unlock_irqrestore(&pmu_lock, flags);
+}
+
+static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev)
+{
+       unsigned long pmnc;
+       struct perf_sample_data data;
+       struct cpu_hw_events *cpuc;
+       struct pt_regs *regs;
+       int idx;
+
+       /*
+        * Get and reset the IRQ flags
+        */
+       pmnc = armv7_pmnc_getreset_flags();
+
+       /*
+        * Did an overflow occur?
+        */
+       if (!armv7_pmnc_has_overflowed(pmnc))
+               return IRQ_NONE;
+
+       /*
+        * Handle the counter(s) overflow(s)
+        */
+       regs = get_irq_regs();
+
+       data.addr = 0;
+
+       cpuc = &__get_cpu_var(cpu_hw_events);
+       for (idx = 0; idx <= armpmu->num_events; ++idx) {
+               struct perf_event *event = cpuc->events[idx];
+               struct hw_perf_event *hwc;
+
+               if (!test_bit(idx, cpuc->active_mask))
+                       continue;
+
+               /*
+                * We have a single interrupt for all counters. Check that
+                * each counter has overflowed before we process it.
+                */
+               if (!armv7_pmnc_counter_has_overflowed(pmnc, idx))
+                       continue;
+
+               hwc = &event->hw;
+               armpmu_event_update(event, hwc, idx);
+               data.period = event->hw.last_period;
+               if (!armpmu_event_set_period(event, hwc, idx))
+                       continue;
+
+               if (perf_event_overflow(event, 0, &data, regs))
+                       armpmu->disable(hwc, idx);
+       }
+
+       /*
+        * Handle the pending perf events.
+        *
+        * Note: this call *must* be run with interrupts enabled. For
+        * platforms that can have the PMU interrupts raised as a PMI, this
+        * will not work.
+        */
+       perf_event_do_pending();
+
+       return IRQ_HANDLED;
+}
+
+static void armv7pmu_start(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&pmu_lock, flags);
+       /* Enable all counters */
+       armv7_pmnc_write(armv7_pmnc_read() | ARMV7_PMNC_E);
+       spin_unlock_irqrestore(&pmu_lock, flags);
+}
+
+static void armv7pmu_stop(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&pmu_lock, flags);
+       /* Disable all counters */
+       armv7_pmnc_write(armv7_pmnc_read() & ~ARMV7_PMNC_E);
+       spin_unlock_irqrestore(&pmu_lock, flags);
+}
+
+static inline int armv7_a8_pmu_event_map(int config)
+{
+       int mapping = armv7_a8_perf_map[config];
+       if (HW_OP_UNSUPPORTED == mapping)
+               mapping = -EOPNOTSUPP;
+       return mapping;
+}
+
+static inline int armv7_a9_pmu_event_map(int config)
+{
+       int mapping = armv7_a9_perf_map[config];
+       if (HW_OP_UNSUPPORTED == mapping)
+               mapping = -EOPNOTSUPP;
+       return mapping;
+}
+
+static u64 armv7pmu_raw_event(u64 config)
+{
+       return config & 0xff;
+}
+
+static int armv7pmu_get_event_idx(struct cpu_hw_events *cpuc,
+                                 struct hw_perf_event *event)
+{
+       int idx;
+
+       /* Always place a cycle counter into the cycle counter. */
+       if (event->config_base == ARMV7_PERFCTR_CPU_CYCLES) {
+               if (test_and_set_bit(ARMV7_CYCLE_COUNTER, cpuc->used_mask))
+                       return -EAGAIN;
+
+               return ARMV7_CYCLE_COUNTER;
+       } else {
+               /*
+                * For anything other than a cycle counter, try and use
+                * the events counters
+                */
+               for (idx = ARMV7_COUNTER0; idx <= armpmu->num_events; ++idx) {
+                       if (!test_and_set_bit(idx, cpuc->used_mask))
+                               return idx;
+               }
+
+               /* The counters are all in use. */
+               return -EAGAIN;
+       }
+}
+
+static struct arm_pmu armv7pmu = {
+       .handle_irq             = armv7pmu_handle_irq,
+       .enable                 = armv7pmu_enable_event,
+       .disable                = armv7pmu_disable_event,
+       .raw_event              = armv7pmu_raw_event,
+       .read_counter           = armv7pmu_read_counter,
+       .write_counter          = armv7pmu_write_counter,
+       .get_event_idx          = armv7pmu_get_event_idx,
+       .start                  = armv7pmu_start,
+       .stop                   = armv7pmu_stop,
+       .max_period             = (1LLU << 32) - 1,
+};
+
+static u32 __init armv7_reset_read_pmnc(void)
+{
+       u32 nb_cnt;
+
+       /* Initialize & Reset PMNC: C and P bits */
+       armv7_pmnc_write(ARMV7_PMNC_P | ARMV7_PMNC_C);
+
+       /* Read the nb of CNTx counters supported from PMNC */
+       nb_cnt = (armv7_pmnc_read() >> ARMV7_PMNC_N_SHIFT) & ARMV7_PMNC_N_MASK;
+
+       /* Add the CPU cycles counter and return */
+       return nb_cnt + 1;
+}
+
+static int __init
+init_hw_perf_events(void)
+{
+       unsigned long cpuid = read_cpuid_id();
+       unsigned long implementor = (cpuid & 0xFF000000) >> 24;
+       unsigned long part_number = (cpuid & 0xFFF0);
+
+       /* We only support ARM CPUs implemented by ARM at the moment. */
+       if (0x41 == implementor) {
+               switch (part_number) {
+               case 0xB360:    /* ARM1136 */
+               case 0xB560:    /* ARM1156 */
+               case 0xB760:    /* ARM1176 */
+                       armpmu = &armv6pmu;
+                       memcpy(armpmu_perf_cache_map, armv6_perf_cache_map,
+                                       sizeof(armv6_perf_cache_map));
+                       perf_max_events = armv6pmu.num_events;
+                       break;
+               case 0xB020:    /* ARM11mpcore */
+                       armpmu = &armv6mpcore_pmu;
+                       memcpy(armpmu_perf_cache_map,
+                              armv6mpcore_perf_cache_map,
+                              sizeof(armv6mpcore_perf_cache_map));
+                       perf_max_events = armv6mpcore_pmu.num_events;
+                       break;
+               case 0xC080:    /* Cortex-A8 */
+                       armv7pmu.name = ARMV7_PMU_CORTEX_A8_NAME;
+                       memcpy(armpmu_perf_cache_map, armv7_a8_perf_cache_map,
+                               sizeof(armv7_a8_perf_cache_map));
+                       armv7pmu.event_map = armv7_a8_pmu_event_map;
+                       armpmu = &armv7pmu;
+
+                       /* Reset PMNC and read the nb of CNTx counters
+                           supported */
+                       armv7pmu.num_events = armv7_reset_read_pmnc();
+                       perf_max_events = armv7pmu.num_events;
+                       break;
+               case 0xC090:    /* Cortex-A9 */
+                       armv7pmu.name = ARMV7_PMU_CORTEX_A9_NAME;
+                       memcpy(armpmu_perf_cache_map, armv7_a9_perf_cache_map,
+                               sizeof(armv7_a9_perf_cache_map));
+                       armv7pmu.event_map = armv7_a9_pmu_event_map;
+                       armpmu = &armv7pmu;
+
+                       /* Reset PMNC and read the nb of CNTx counters
+                           supported */
+                       armv7pmu.num_events = armv7_reset_read_pmnc();
+                       perf_max_events = armv7pmu.num_events;
+                       break;
+               default:
+                       pr_info("no hardware support available\n");
+                       perf_max_events = -1;
+               }
+       }
+
+       if (armpmu)
+               pr_info("enabled with %s PMU driver, %d counters available\n",
+                       armpmu->name, armpmu->num_events);
+
+       return 0;
+}
+arch_initcall(init_hw_perf_events);
+
+/*
+ * Callchain handling code.
+ */
+static inline void
+callchain_store(struct perf_callchain_entry *entry,
+               u64 ip)
+{
+       if (entry->nr < PERF_MAX_STACK_DEPTH)
+               entry->ip[entry->nr++] = ip;
+}
+
+/*
+ * The registers we're interested in are at the end of the variable
+ * length saved register structure. The fp points at the end of this
+ * structure so the address of this struct is:
+ * (struct frame_tail *)(xxx->fp)-1
+ *
+ * This code has been adapted from the ARM OProfile support.
+ */
+struct frame_tail {
+       struct frame_tail   *fp;
+       unsigned long       sp;
+       unsigned long       lr;
+} __attribute__((packed));
+
+/*
+ * Get the return address for a single stackframe and return a pointer to the
+ * next frame tail.
+ */
+static struct frame_tail *
+user_backtrace(struct frame_tail *tail,
+              struct perf_callchain_entry *entry)
+{
+       struct frame_tail buftail;
+
+       /* Also check accessibility of one struct frame_tail beyond */
+       if (!access_ok(VERIFY_READ, tail, sizeof(buftail)))
+               return NULL;
+       if (__copy_from_user_inatomic(&buftail, tail, sizeof(buftail)))
+               return NULL;
+
+       callchain_store(entry, buftail.lr);
+
+       /*
+        * Frame pointers should strictly progress back up the stack
+        * (towards higher addresses).
+        */
+       if (tail >= buftail.fp)
+               return NULL;
+
+       return buftail.fp - 1;
+}
+
+static void
+perf_callchain_user(struct pt_regs *regs,
+                   struct perf_callchain_entry *entry)
+{
+       struct frame_tail *tail;
+
+       callchain_store(entry, PERF_CONTEXT_USER);
+
+       if (!user_mode(regs))
+               regs = task_pt_regs(current);
+
+       tail = (struct frame_tail *)regs->ARM_fp - 1;
+
+       while (tail && !((unsigned long)tail & 0x3))
+               tail = user_backtrace(tail, entry);
+}
+
+/*
+ * Gets called by walk_stackframe() for every stackframe. This will be called
+ * whist unwinding the stackframe and is like a subroutine return so we use
+ * the PC.
+ */
+static int
+callchain_trace(struct stackframe *fr,
+               void *data)
+{
+       struct perf_callchain_entry *entry = data;
+       callchain_store(entry, fr->pc);
+       return 0;
+}
+
+static void
+perf_callchain_kernel(struct pt_regs *regs,
+                     struct perf_callchain_entry *entry)
+{
+       struct stackframe fr;
+
+       callchain_store(entry, PERF_CONTEXT_KERNEL);
+       fr.fp = regs->ARM_fp;
+       fr.sp = regs->ARM_sp;
+       fr.lr = regs->ARM_lr;
+       fr.pc = regs->ARM_pc;
+       walk_stackframe(&fr, callchain_trace, entry);
+}
+
+static void
+perf_do_callchain(struct pt_regs *regs,
+                 struct perf_callchain_entry *entry)
+{
+       int is_user;
+
+       if (!regs)
+               return;
+
+       is_user = user_mode(regs);
+
+       if (!current || !current->pid)
+               return;
+
+       if (is_user && current->state != TASK_RUNNING)
+               return;
+
+       if (!is_user)
+               perf_callchain_kernel(regs, entry);
+
+       if (current->mm)
+               perf_callchain_user(regs, entry);
+}
+
+static DEFINE_PER_CPU(struct perf_callchain_entry, pmc_irq_entry);
+
+struct perf_callchain_entry *
+perf_callchain(struct pt_regs *regs)
+{
+       struct perf_callchain_entry *entry = &__get_cpu_var(pmc_irq_entry);
+
+       entry->nr = 0;
+       perf_do_callchain(regs, entry);
+       return entry;
+}
diff --git a/arch/arm/kernel/pmu.c b/arch/arm/kernel/pmu.c
new file mode 100644 (file)
index 0000000..a124312
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ *  linux/arch/arm/kernel/pmu.c
+ *
+ *  Copyright (C) 2009 picoChip Designs Ltd, Jamie Iles
+ *
+ * This program is free software; you can 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/cpumask.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <asm/pmu.h>
+
+/*
+ * Define the IRQs for the system. We could use something like a platform
+ * device but that seems fairly heavyweight for this. Also, the performance
+ * counters can't be removed or hotplugged.
+ *
+ * Ordering is important: init_pmu() will use the ordering to set the affinity
+ * to the corresponding core. e.g. the first interrupt will go to cpu 0, the
+ * second goes to cpu 1 etc.
+ */
+static const int irqs[] = {
+#if defined(CONFIG_ARCH_OMAP2)
+       3,
+#elif defined(CONFIG_ARCH_BCMRING)
+       IRQ_PMUIRQ,
+#elif defined(CONFIG_MACH_REALVIEW_EB)
+       IRQ_EB11MP_PMU_CPU0,
+       IRQ_EB11MP_PMU_CPU1,
+       IRQ_EB11MP_PMU_CPU2,
+       IRQ_EB11MP_PMU_CPU3,
+#elif defined(CONFIG_ARCH_OMAP3)
+       INT_34XX_BENCH_MPU_EMUL,
+#elif defined(CONFIG_ARCH_IOP32X)
+       IRQ_IOP32X_CORE_PMU,
+#elif defined(CONFIG_ARCH_IOP33X)
+       IRQ_IOP33X_CORE_PMU,
+#elif defined(CONFIG_ARCH_PXA)
+       IRQ_PMU,
+#endif
+};
+
+static const struct pmu_irqs pmu_irqs = {
+       .irqs       = irqs,
+       .num_irqs   = ARRAY_SIZE(irqs),
+};
+
+static volatile long pmu_lock;
+
+const struct pmu_irqs *
+reserve_pmu(void)
+{
+       return test_and_set_bit_lock(0, &pmu_lock) ? ERR_PTR(-EBUSY) :
+               &pmu_irqs;
+}
+EXPORT_SYMBOL_GPL(reserve_pmu);
+
+int
+release_pmu(const struct pmu_irqs *irqs)
+{
+       if (WARN_ON(irqs != &pmu_irqs))
+               return -EINVAL;
+       clear_bit_unlock(0, &pmu_lock);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(release_pmu);
+
+static int
+set_irq_affinity(int irq,
+                unsigned int cpu)
+{
+#ifdef CONFIG_SMP
+       int err = irq_set_affinity(irq, cpumask_of(cpu));
+       if (err)
+               pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n",
+                          irq, cpu);
+       return err;
+#else
+       return 0;
+#endif
+}
+
+int
+init_pmu(void)
+{
+       int i, err = 0;
+
+       for (i = 0; i < pmu_irqs.num_irqs; ++i) {
+               err = set_irq_affinity(pmu_irqs.irqs[i], i);
+               if (err)
+                       break;
+       }
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(init_pmu);
index a2ea3854cb3c8379120abaa94ab6c47fdc91ad67..08f899fb76a69d0ab48026950642fb8e733e4d92 100644 (file)
@@ -499,10 +499,41 @@ static struct undef_hook thumb_break_hook = {
        .fn             = break_trap,
 };
 
+static int thumb2_break_trap(struct pt_regs *regs, unsigned int instr)
+{
+       unsigned int instr2;
+       void __user *pc;
+
+       /* Check the second half of the instruction.  */
+       pc = (void __user *)(instruction_pointer(regs) + 2);
+
+       if (processor_mode(regs) == SVC_MODE) {
+               instr2 = *(u16 *) pc;
+       } else {
+               get_user(instr2, (u16 __user *)pc);
+       }
+
+       if (instr2 == 0xa000) {
+               ptrace_break(current, regs);
+               return 0;
+       } else {
+               return 1;
+       }
+}
+
+static struct undef_hook thumb2_break_hook = {
+       .instr_mask     = 0xffff,
+       .instr_val      = 0xf7f0,
+       .cpsr_mask      = PSR_T_BIT,
+       .cpsr_val       = PSR_T_BIT,
+       .fn             = thumb2_break_trap,
+};
+
 static int __init ptrace_break_init(void)
 {
        register_undef_hook(&arm_break_hook);
        register_undef_hook(&thumb_break_hook);
+       register_undef_hook(&thumb2_break_hook);
        return 0;
 }
 
@@ -669,7 +700,7 @@ static int ptrace_getvfpregs(struct task_struct *tsk, void __user *data)
        union vfp_state *vfp = &thread->vfpstate;
        struct user_vfp __user *ufp = data;
 
-       vfp_sync_state(thread);
+       vfp_sync_hwstate(thread);
 
        /* copy the floating point registers */
        if (copy_to_user(&ufp->fpregs, &vfp->hard.fpregs,
@@ -692,7 +723,7 @@ static int ptrace_setvfpregs(struct task_struct *tsk, void __user *data)
        union vfp_state *vfp = &thread->vfpstate;
        struct user_vfp __user *ufp = data;
 
-       vfp_sync_state(thread);
+       vfp_sync_hwstate(thread);
 
        /* copy the floating point registers */
        if (copy_from_user(&vfp->hard.fpregs, &ufp->fpregs,
@@ -703,6 +734,8 @@ static int ptrace_setvfpregs(struct task_struct *tsk, void __user *data)
        if (get_user(vfp->hard.fpscr, &ufp->fpscr))
                return -EFAULT;
 
+       vfp_flush_hwstate(thread);
+
        return 0;
 }
 #endif
@@ -712,26 +745,10 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
        int ret;
 
        switch (request) {
-               /*
-                * read word at location "addr" in the child process.
-                */
-               case PTRACE_PEEKTEXT:
-               case PTRACE_PEEKDATA:
-                       ret = generic_ptrace_peekdata(child, addr, data);
-                       break;
-
                case PTRACE_PEEKUSR:
                        ret = ptrace_read_user(child, addr, (unsigned long __user *)data);
                        break;
 
-               /*
-                * write the word at location addr.
-                */
-               case PTRACE_POKETEXT:
-               case PTRACE_POKEDATA:
-                       ret = generic_ptrace_pokedata(child, addr, data);
-                       break;
-
                case PTRACE_POKEUSR:
                        ret = ptrace_write_user(child, addr, data);
                        break;
index 621acad8ea43c274b948c275c9de46177a42542e..c91c77b54dea151be9e04bee8355d0d78d3b1445 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/interrupt.h>
 #include <linux/smp.h>
 #include <linux/fs.h>
+#include <linux/proc_fs.h>
 
 #include <asm/unified.h>
 #include <asm/cpu.h>
@@ -118,7 +119,7 @@ EXPORT_SYMBOL(elf_platform);
 
 static const char *cpu_name;
 static const char *machine_name;
-static char __initdata command_line[COMMAND_LINE_SIZE];
+static char __initdata cmd_line[COMMAND_LINE_SIZE];
 
 static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
 static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } };
@@ -418,10 +419,11 @@ static int __init arm_add_memory(unsigned long start, unsigned long size)
  * Pick out the memory size.  We look for mem=size@start,
  * where start and size are "size[KkMm]"
  */
-static void __init early_mem(char **p)
+static int __init early_mem(char *p)
 {
        static int usermem __initdata = 0;
        unsigned long size, start;
+       char *endp;
 
        /*
         * If the user specifies memory size, we
@@ -434,52 +436,15 @@ static void __init early_mem(char **p)
        }
 
        start = PHYS_OFFSET;
-       size  = memparse(*p, p);
-       if (**p == '@')
-               start = memparse(*p + 1, p);
+       size  = memparse(p, &endp);
+       if (*endp == '@')
+               start = memparse(endp + 1, NULL);
 
        arm_add_memory(start, size);
-}
-__early_param("mem=", early_mem);
 
-/*
- * Initial parsing of the command line.
- */
-static void __init parse_cmdline(char **cmdline_p, char *from)
-{
-       char c = ' ', *to = command_line;
-       int len = 0;
-
-       for (;;) {
-               if (c == ' ') {
-                       extern struct early_params __early_begin, __early_end;
-                       struct early_params *p;
-
-                       for (p = &__early_begin; p < &__early_end; p++) {
-                               int arglen = strlen(p->arg);
-
-                               if (memcmp(from, p->arg, arglen) == 0) {
-                                       if (to != command_line)
-                                               to -= 1;
-                                       from += arglen;
-                                       p->fn(&from);
-
-                                       while (*from != ' ' && *from != '\0')
-                                               from++;
-                                       break;
-                               }
-                       }
-               }
-               c = *from++;
-               if (!c)
-                       break;
-               if (COMMAND_LINE_SIZE <= ++len)
-                       break;
-               *to++ = c;
-       }
-       *to = '\0';
-       *cmdline_p = command_line;
+       return 0;
 }
+early_param("mem", early_mem);
 
 static void __init
 setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)
@@ -740,9 +705,15 @@ void __init setup_arch(char **cmdline_p)
        init_mm.end_data   = (unsigned long) _edata;
        init_mm.brk        = (unsigned long) _end;
 
-       memcpy(boot_command_line, from, COMMAND_LINE_SIZE);
-       boot_command_line[COMMAND_LINE_SIZE-1] = '\0';
-       parse_cmdline(cmdline_p, from);
+       /* parse_early_param needs a boot_command_line */
+       strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);
+
+       /* populate cmd_line too for later use, preserving boot_command_line */
+       strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
+       *cmdline_p = cmd_line;
+
+       parse_early_param();
+
        paging_init(mdesc);
        request_standard_resources(&meminfo, mdesc);
 
@@ -783,9 +754,21 @@ static int __init topology_init(void)
 
        return 0;
 }
-
 subsys_initcall(topology_init);
 
+#ifdef CONFIG_HAVE_PROC_CPU
+static int __init proc_cpu_init(void)
+{
+       struct proc_dir_entry *res;
+
+       res = proc_mkdir("cpu", NULL);
+       if (!res)
+               return -ENOMEM;
+       return 0;
+}
+fs_initcall(proc_cpu_init);
+#endif
+
 static const char *hwcap_str[] = {
        "swp",
        "half",
index d38cdf2c8276e6e23c769b9cf494dad5ff803d1f..28753805d2d16f7cffa9fd25b4164011432b014b 100644 (file)
  *
  *  This file contains the ARM-specific time handling details:
  *  reading the RTC at bootup, etc...
- *
- *  1994-07-02  Alan Modra
- *              fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
- *  1998-12-20  Updated NTP code according to technical memorandum Jan '96
- *              "A Kernel Model for Precision Timekeeping" by Dave Mills
  */
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -77,11 +72,6 @@ unsigned long profile_pc(struct pt_regs *regs)
 EXPORT_SYMBOL(profile_pc);
 #endif
 
-/*
- * hook for setting the RTC's idea of the current time.
- */
-int (*set_rtc)(void);
-
 #ifndef CONFIG_GENERIC_TIME
 static unsigned long dummy_gettimeoffset(void)
 {
@@ -89,140 +79,6 @@ static unsigned long dummy_gettimeoffset(void)
 }
 #endif
 
-static unsigned long next_rtc_update;
-
-/*
- * If we have an externally synchronized linux clock, then update
- * CMOS clock accordingly every ~11 minutes.  set_rtc() has to be
- * called as close as possible to 500 ms before the new second
- * starts.
- */
-static inline void do_set_rtc(void)
-{
-       if (!ntp_synced() || set_rtc == NULL)
-               return;
-
-       if (next_rtc_update &&
-           time_before((unsigned long)xtime.tv_sec, next_rtc_update))
-               return;
-
-       if (xtime.tv_nsec < 500000000 - ((unsigned) tick_nsec >> 1) &&
-           xtime.tv_nsec >= 500000000 + ((unsigned) tick_nsec >> 1))
-               return;
-
-       if (set_rtc())
-               /*
-                * rtc update failed.  Try again in 60s
-                */
-               next_rtc_update = xtime.tv_sec + 60;
-       else
-               next_rtc_update = xtime.tv_sec + 660;
-}
-
-#ifdef CONFIG_LEDS
-
-static void dummy_leds_event(led_event_t evt)
-{
-}
-
-void (*leds_event)(led_event_t) = dummy_leds_event;
-
-struct leds_evt_name {
-       const char      name[8];
-       int             on;
-       int             off;
-};
-
-static const struct leds_evt_name evt_names[] = {
-       { "amber", led_amber_on, led_amber_off },
-       { "blue",  led_blue_on,  led_blue_off  },
-       { "green", led_green_on, led_green_off },
-       { "red",   led_red_on,   led_red_off   },
-};
-
-static ssize_t leds_store(struct sys_device *dev,
-                       struct sysdev_attribute *attr,
-                       const char *buf, size_t size)
-{
-       int ret = -EINVAL, len = strcspn(buf, " ");
-
-       if (len > 0 && buf[len] == '\0')
-               len--;
-
-       if (strncmp(buf, "claim", len) == 0) {
-               leds_event(led_claim);
-               ret = size;
-       } else if (strncmp(buf, "release", len) == 0) {
-               leds_event(led_release);
-               ret = size;
-       } else {
-               int i;
-
-               for (i = 0; i < ARRAY_SIZE(evt_names); i++) {
-                       if (strlen(evt_names[i].name) != len ||
-                           strncmp(buf, evt_names[i].name, len) != 0)
-                               continue;
-                       if (strncmp(buf+len, " on", 3) == 0) {
-                               leds_event(evt_names[i].on);
-                               ret = size;
-                       } else if (strncmp(buf+len, " off", 4) == 0) {
-                               leds_event(evt_names[i].off);
-                               ret = size;
-                       }
-                       break;
-               }
-       }
-       return ret;
-}
-
-static SYSDEV_ATTR(event, 0200, NULL, leds_store);
-
-static int leds_suspend(struct sys_device *dev, pm_message_t state)
-{
-       leds_event(led_stop);
-       return 0;
-}
-
-static int leds_resume(struct sys_device *dev)
-{
-       leds_event(led_start);
-       return 0;
-}
-
-static int leds_shutdown(struct sys_device *dev)
-{
-       leds_event(led_halted);
-       return 0;
-}
-
-static struct sysdev_class leds_sysclass = {
-       .name           = "leds",
-       .shutdown       = leds_shutdown,
-       .suspend        = leds_suspend,
-       .resume         = leds_resume,
-};
-
-static struct sys_device leds_device = {
-       .id             = 0,
-       .cls            = &leds_sysclass,
-};
-
-static int __init leds_init(void)
-{
-       int ret;
-       ret = sysdev_class_register(&leds_sysclass);
-       if (ret == 0)
-               ret = sysdev_register(&leds_device);
-       if (ret == 0)
-               ret = sysdev_create_file(&leds_device, &attr_event);
-       return ret;
-}
-
-device_initcall(leds_init);
-
-EXPORT_SYMBOL(leds_event);
-#endif
-
 #ifdef CONFIG_LEDS_TIMER
 static inline void do_leds(void)
 {
@@ -295,39 +151,6 @@ int do_settimeofday(struct timespec *tv)
 EXPORT_SYMBOL(do_settimeofday);
 #endif /* !CONFIG_GENERIC_TIME */
 
-/**
- * save_time_delta - Save the offset between system time and RTC time
- * @delta: pointer to timespec to store delta
- * @rtc: pointer to timespec for current RTC time
- *
- * Return a delta between the system time and the RTC time, such
- * that system time can be restored later with restore_time_delta()
- */
-void save_time_delta(struct timespec *delta, struct timespec *rtc)
-{
-       set_normalized_timespec(delta,
-                               xtime.tv_sec - rtc->tv_sec,
-                               xtime.tv_nsec - rtc->tv_nsec);
-}
-EXPORT_SYMBOL(save_time_delta);
-
-/**
- * restore_time_delta - Restore the current system time
- * @delta: delta returned by save_time_delta()
- * @rtc: pointer to timespec for current RTC time
- */
-void restore_time_delta(struct timespec *delta, struct timespec *rtc)
-{
-       struct timespec ts;
-
-       set_normalized_timespec(&ts,
-                               delta->tv_sec + rtc->tv_sec,
-                               delta->tv_nsec + rtc->tv_nsec);
-
-       do_settimeofday(&ts);
-}
-EXPORT_SYMBOL(restore_time_delta);
-
 #ifndef CONFIG_GENERIC_CLOCKEVENTS
 /*
  * Kernel system timer support.
@@ -336,7 +159,6 @@ void timer_tick(void)
 {
        profile_tick(CPU_PROFILING);
        do_leds();
-       do_set_rtc();
        write_seqlock(&xtime_lock);
        do_timer(1);
        write_sequnlock(&xtime_lock);
index 3f361a783f43a6b9bea075e035e5405649b185dd..1621e5327b2a72a6c9197e95615928e749aa5f41 100644 (file)
  *  'linux/arch/arm/lib/traps.S'.  Mostly a debugging aid, but will probably
  *  kill the offending process.
  */
-#include <linux/module.h>
 #include <linux/signal.h>
-#include <linux/spinlock.h>
 #include <linux/personality.h>
 #include <linux/kallsyms.h>
-#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
 #include <linux/hardirq.h>
+#include <linux/kdebug.h>
+#include <linux/module.h>
+#include <linux/kexec.h>
+#include <linux/delay.h>
 #include <linux/init.h>
-#include <linux/uaccess.h>
 
 #include <asm/atomic.h>
 #include <asm/cacheflush.h>
@@ -224,14 +226,21 @@ void show_stack(struct task_struct *tsk, unsigned long *sp)
 #define S_SMP ""
 #endif
 
-static void __die(const char *str, int err, struct thread_info *thread, struct pt_regs *regs)
+static int __die(const char *str, int err, struct thread_info *thread, struct pt_regs *regs)
 {
        struct task_struct *tsk = thread->task;
        static int die_counter;
+       int ret;
 
        printk(KERN_EMERG "Internal error: %s: %x [#%d]" S_PREEMPT S_SMP "\n",
               str, err, ++die_counter);
        sysfs_printk_last_file();
+
+       /* trap and error numbers are mostly meaningless on ARM */
+       ret = notify_die(DIE_OOPS, str, regs, err, tsk->thread.trap_no, SIGSEGV);
+       if (ret == NOTIFY_STOP)
+               return ret;
+
        print_modules();
        __show_regs(regs);
        printk(KERN_EMERG "Process %.*s (pid: %d, stack limit = 0x%p)\n",
@@ -243,6 +252,8 @@ static void __die(const char *str, int err, struct thread_info *thread, struct p
                dump_backtrace(regs, tsk);
                dump_instr(KERN_EMERG, regs);
        }
+
+       return ret;
 }
 
 DEFINE_SPINLOCK(die_lock);
@@ -250,16 +261,21 @@ DEFINE_SPINLOCK(die_lock);
 /*
  * This function is protected against re-entrancy.
  */
-NORET_TYPE void die(const char *str, struct pt_regs *regs, int err)
+void die(const char *str, struct pt_regs *regs, int err)
 {
        struct thread_info *thread = current_thread_info();
+       int ret;
 
        oops_enter();
 
        spin_lock_irq(&die_lock);
        console_verbose();
        bust_spinlocks(1);
-       __die(str, err, thread, regs);
+       ret = __die(str, err, thread, regs);
+
+       if (regs && kexec_should_crash(thread->task))
+               crash_kexec(regs);
+
        bust_spinlocks(0);
        add_taint(TAINT_DIE);
        spin_unlock_irq(&die_lock);
@@ -267,11 +283,10 @@ NORET_TYPE void die(const char *str, struct pt_regs *regs, int err)
 
        if (in_interrupt())
                panic("Fatal exception in interrupt");
-
        if (panic_on_oops)
                panic("Fatal exception");
-
-       do_exit(SIGSEGV);
+       if (ret != NOTIFY_STOP)
+               do_exit(SIGSEGV);
 }
 
 void arm_notify_die(const char *str, struct pt_regs *regs,
index 4957e13ef55ba6be1d396f5dc72d3eebb2b43450..b16c07914b55bb0215592a7727e0974b62108dd6 100644 (file)
@@ -43,10 +43,6 @@ SECTIONS
 
                INIT_SETUP(16)
 
-               __early_begin = .;
-                       *(.early_param.init)
-               __early_end = .;
-
                INIT_CALLS
                CON_INITCALL
                SECURITY_INITCALL
index 0b6351d7c38973e7431c601e291afab173d54551..a9cac368bfe69f184c85ce7058ec29cfe10c83a2 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 #include "hardware.h"
-               .macro  addruart,rx
+               .macro  addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                 @ MMU enabled?
                moveq   \rx, #0x80000000                @ physical
index 0b2ee953f1641d75d4d0fc9ddcc655758a9b02df..2db43a5ddd9b7b752b054ded6ff3c32f2c6c3de7 100644 (file)
@@ -89,6 +89,12 @@ config ARCH_AT91CAP9
        select GENERIC_CLOCKEVENTS
        select HAVE_FB_ATMEL
 
+config ARCH_AT572D940HF
+       bool "AT572D940HF"
+       select CPU_ARM926T
+       select GENERIC_TIME
+       select GENERIC_CLOCKEVENTS
+
 config ARCH_AT91X40
        bool "AT91x40"
 
@@ -390,6 +396,23 @@ endif
 
 # ----------------------------------------------------------
 
+if ARCH_AT572D940HF
+
+comment "AT572D940HF Board Type"
+
+config MACH_AT572D940HFEB
+       bool "AT572D940HF-EK"
+       depends on ARCH_AT572D940HF
+       select HAVE_AT91_DATAFLASH_CARD
+       select HAVE_NAND_ATMEL_BUSWIDTH_16
+       help
+         Select this if you are using Atmel's AT572D940HF-EK evaluation kit.
+         <http://www.atmel.com/products/diopsis/default.asp>
+
+endif
+
+# ----------------------------------------------------------
+
 if ARCH_AT91X40
 
 comment "AT91X40 Board Type"
index 709fbad4a3ee2b28b14ec7fd0281dc4382702c76..027dd570dcc30231059d3530f5a33293f168dce7 100644 (file)
@@ -19,6 +19,7 @@ obj-$(CONFIG_ARCH_AT91SAM9RL) += at91sam9rl.o at91sam926x_time.o at91sam9rl_devi
 obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o  sam9_smc.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
 obj-$(CONFIG_ARCH_AT91X40)     += at91x40.o at91x40_time.o
 
 # AT91RM9200 board-specific support
@@ -69,6 +70,9 @@ obj-$(CONFIG_MACH_AT91SAM9G45EKES) += board-sam9m10g45ek.o
 # AT91CAP9 board-specific support
 obj-$(CONFIG_MACH_AT91CAP9ADK) += board-cap9adk.o
 
+# AT572D940HF board-specific support
+obj-$(CONFIG_MACH_AT572D940HFEB) += board-at572d940hf_ek.o
+
 # AT91X40 board-specific support
 obj-$(CONFIG_MACH_AT91EB01)    += board-eb01.o
 
diff --git a/arch/arm/mach-at91/at572d940hf.c b/arch/arm/mach-at91/at572d940hf.c
new file mode 100644 (file)
index 0000000..a6b9c68
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+ * arch/arm/mach-at91/at572d940hf.c
+ *
+ * Antonio R. Costa <costa.antonior@gmail.com>
+ * Copyright (C) 2008 Atmel
+ *
+ * Copyright (C) 2005 SAN People
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/module.h>
+
+#include <asm/mach/irq.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <mach/at572d940hf.h>
+#include <mach/at91_pmc.h>
+#include <mach/at91_rstc.h>
+
+#include "generic.h"
+#include "clock.h"
+
+static struct map_desc at572d940hf_io_desc[] __initdata = {
+       {
+               .virtual        = AT91_VA_BASE_SYS,
+               .pfn            = __phys_to_pfn(AT91_BASE_SYS),
+               .length         = SZ_16K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = AT91_IO_VIRT_BASE - AT572D940HF_SRAM_SIZE,
+               .pfn            = __phys_to_pfn(AT572D940HF_SRAM_BASE),
+               .length         = AT572D940HF_SRAM_SIZE,
+               .type           = MT_DEVICE,
+       },
+};
+
+/* --------------------------------------------------------------------
+ *  Clocks
+ * -------------------------------------------------------------------- */
+
+/*
+ * The peripheral clocks.
+ */
+static struct clk pioA_clk = {
+       .name           = "pioA_clk",
+       .pmc_mask       = 1 << AT572D940HF_ID_PIOA,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk pioB_clk = {
+       .name           = "pioB_clk",
+       .pmc_mask       = 1 << AT572D940HF_ID_PIOB,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk pioC_clk = {
+       .name           = "pioC_clk",
+       .pmc_mask       = 1 << AT572D940HF_ID_PIOC,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk macb_clk = {
+       .name           = "macb_clk",
+       .pmc_mask       = 1 << AT572D940HF_ID_EMAC,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart0_clk = {
+       .name           = "usart0_clk",
+       .pmc_mask       = 1 << AT572D940HF_ID_US0,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart1_clk = {
+       .name           = "usart1_clk",
+       .pmc_mask       = 1 << AT572D940HF_ID_US1,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart2_clk = {
+       .name           = "usart2_clk",
+       .pmc_mask       = 1 << AT572D940HF_ID_US2,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk mmc_clk = {
+       .name           = "mci_clk",
+       .pmc_mask       = 1 << AT572D940HF_ID_MCI,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk udc_clk = {
+       .name           = "udc_clk",
+       .pmc_mask       = 1 << AT572D940HF_ID_UDP,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk twi0_clk = {
+       .name           = "twi0_clk",
+       .pmc_mask       = 1 << AT572D940HF_ID_TWI0,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk spi0_clk = {
+       .name           = "spi0_clk",
+       .pmc_mask       = 1 << AT572D940HF_ID_SPI0,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk spi1_clk = {
+       .name           = "spi1_clk",
+       .pmc_mask       = 1 << AT572D940HF_ID_SPI1,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk ssc0_clk = {
+       .name           = "ssc0_clk",
+       .pmc_mask       = 1 << AT572D940HF_ID_SSC0,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk ssc1_clk = {
+       .name           = "ssc1_clk",
+       .pmc_mask       = 1 << AT572D940HF_ID_SSC1,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk ssc2_clk = {
+       .name           = "ssc2_clk",
+       .pmc_mask       = 1 << AT572D940HF_ID_SSC2,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk tc0_clk = {
+       .name           = "tc0_clk",
+       .pmc_mask       = 1 << AT572D940HF_ID_TC0,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk tc1_clk = {
+       .name           = "tc1_clk",
+       .pmc_mask       = 1 << AT572D940HF_ID_TC1,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk tc2_clk = {
+       .name           = "tc2_clk",
+       .pmc_mask       = 1 << AT572D940HF_ID_TC2,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk ohci_clk = {
+       .name           = "ohci_clk",
+       .pmc_mask       = 1 << AT572D940HF_ID_UHP,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk ssc3_clk = {
+       .name           = "ssc3_clk",
+       .pmc_mask       = 1 << AT572D940HF_ID_SSC3,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk twi1_clk = {
+       .name           = "twi1_clk",
+       .pmc_mask       = 1 << AT572D940HF_ID_TWI1,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk can0_clk = {
+       .name           = "can0_clk",
+       .pmc_mask       = 1 << AT572D940HF_ID_CAN0,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk can1_clk = {
+       .name           = "can1_clk",
+       .pmc_mask       = 1 << AT572D940HF_ID_CAN1,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk mAgicV_clk = {
+       .name           = "mAgicV_clk",
+       .pmc_mask       = 1 << AT572D940HF_ID_MSIRQ0,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+
+
+static struct clk *periph_clocks[] __initdata = {
+       &pioA_clk,
+       &pioB_clk,
+       &pioC_clk,
+       &macb_clk,
+       &usart0_clk,
+       &usart1_clk,
+       &usart2_clk,
+       &mmc_clk,
+       &udc_clk,
+       &twi0_clk,
+       &spi0_clk,
+       &spi1_clk,
+       &ssc0_clk,
+       &ssc1_clk,
+       &ssc2_clk,
+       &tc0_clk,
+       &tc1_clk,
+       &tc2_clk,
+       &ohci_clk,
+       &ssc3_clk,
+       &twi1_clk,
+       &can0_clk,
+       &can1_clk,
+       &mAgicV_clk,
+       /* irq0 .. irq2 */
+};
+
+/*
+ * The five programmable clocks.
+ * You must configure pin multiplexing to bring these signals out.
+ */
+static struct clk pck0 = {
+       .name           = "pck0",
+       .pmc_mask       = AT91_PMC_PCK0,
+       .type           = CLK_TYPE_PROGRAMMABLE,
+       .id             = 0,
+};
+static struct clk pck1 = {
+       .name           = "pck1",
+       .pmc_mask       = AT91_PMC_PCK1,
+       .type           = CLK_TYPE_PROGRAMMABLE,
+       .id             = 1,
+};
+static struct clk pck2 = {
+       .name           = "pck2",
+       .pmc_mask       = AT91_PMC_PCK2,
+       .type           = CLK_TYPE_PROGRAMMABLE,
+       .id             = 2,
+};
+static struct clk pck3 = {
+       .name           = "pck3",
+       .pmc_mask       = AT91_PMC_PCK3,
+       .type           = CLK_TYPE_PROGRAMMABLE,
+       .id             = 3,
+};
+
+static struct clk mAgicV_mem_clk = {
+       .name           = "mAgicV_mem_clk",
+       .pmc_mask       = AT91_PMC_PCK4,
+       .type           = CLK_TYPE_PROGRAMMABLE,
+       .id             = 4,
+};
+
+/* HClocks */
+static struct clk hck0 = {
+       .name           = "hck0",
+       .pmc_mask       = AT91_PMC_HCK0,
+       .type           = CLK_TYPE_SYSTEM,
+       .id             = 0,
+};
+static struct clk hck1 = {
+       .name           = "hck1",
+       .pmc_mask       = AT91_PMC_HCK1,
+       .type           = CLK_TYPE_SYSTEM,
+       .id             = 1,
+};
+
+static void __init at572d940hf_register_clocks(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
+               clk_register(periph_clocks[i]);
+
+       clk_register(&pck0);
+       clk_register(&pck1);
+       clk_register(&pck2);
+       clk_register(&pck3);
+       clk_register(&mAgicV_mem_clk);
+
+       clk_register(&hck0);
+       clk_register(&hck1);
+}
+
+/* --------------------------------------------------------------------
+ *  GPIO
+ * -------------------------------------------------------------------- */
+
+static struct at91_gpio_bank at572d940hf_gpio[] = {
+       {
+               .id             = AT572D940HF_ID_PIOA,
+               .offset         = AT91_PIOA,
+               .clock          = &pioA_clk,
+       }, {
+               .id             = AT572D940HF_ID_PIOB,
+               .offset         = AT91_PIOB,
+               .clock          = &pioB_clk,
+       }, {
+               .id             = AT572D940HF_ID_PIOC,
+               .offset         = AT91_PIOC,
+               .clock          = &pioC_clk,
+       }
+};
+
+static void at572d940hf_reset(void)
+{
+       at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST);
+}
+
+
+/* --------------------------------------------------------------------
+ *  AT572D940HF processor initialization
+ * -------------------------------------------------------------------- */
+
+void __init at572d940hf_initialize(unsigned long main_clock)
+{
+       /* Map peripherals */
+       iotable_init(at572d940hf_io_desc, ARRAY_SIZE(at572d940hf_io_desc));
+
+       at91_arch_reset = at572d940hf_reset;
+       at91_extern_irq = (1 << AT572D940HF_ID_IRQ0) | (1 << AT572D940HF_ID_IRQ1)
+                       | (1 << AT572D940HF_ID_IRQ2);
+
+       /* Init clock subsystem */
+       at91_clock_init(main_clock);
+
+       /* Register the processor-specific clocks */
+       at572d940hf_register_clocks();
+
+       /* Register GPIO subsystem */
+       at91_gpio_init(at572d940hf_gpio, 3);
+}
+
+/* --------------------------------------------------------------------
+ *  Interrupt initialization
+ * -------------------------------------------------------------------- */
+
+/*
+ * The default interrupt priority levels (0 = lowest, 7 = highest).
+ */
+static unsigned int at572d940hf_default_irq_priority[NR_AIC_IRQS] __initdata = {
+       7,      /* Advanced Interrupt Controller */
+       7,      /* System Peripherals */
+       0,      /* Parallel IO Controller A */
+       0,      /* Parallel IO Controller B */
+       0,      /* Parallel IO Controller C */
+       3,      /* Ethernet */
+       6,      /* USART 0 */
+       6,      /* USART 1 */
+       6,      /* USART 2 */
+       0,      /* Multimedia Card Interface */
+       4,      /* USB Device Port */
+       0,      /* Two-Wire Interface 0 */
+       6,      /* Serial Peripheral Interface 0 */
+       6,      /* Serial Peripheral Interface 1 */
+       5,      /* Serial Synchronous Controller 0 */
+       5,      /* Serial Synchronous Controller 1 */
+       5,      /* Serial Synchronous Controller 2 */
+       0,      /* Timer Counter 0 */
+       0,      /* Timer Counter 1 */
+       0,      /* Timer Counter 2 */
+       3,      /* USB Host port */
+       3,      /* Serial Synchronous Controller 3 */
+       0,      /* Two-Wire Interface 1 */
+       0,      /* CAN Controller 0 */
+       0,      /* CAN Controller 1 */
+       0,      /* mAgicV HALT line */
+       0,      /* mAgicV SIRQ0 line */
+       0,      /* mAgicV exception line */
+       0,      /* mAgicV end of DMA line */
+       0,      /* Advanced Interrupt Controller */
+       0,      /* Advanced Interrupt Controller */
+       0,      /* Advanced Interrupt Controller */
+};
+
+void __init at572d940hf_init_interrupts(unsigned int priority[NR_AIC_IRQS])
+{
+       if (!priority)
+               priority = at572d940hf_default_irq_priority;
+
+       /* Initialize the AIC interrupt controller */
+       at91_aic_init(priority);
+
+       /* Enable GPIO interrupts */
+       at91_gpio_irq_setup();
+}
+
diff --git a/arch/arm/mach-at91/at572d940hf_devices.c b/arch/arm/mach-at91/at572d940hf_devices.c
new file mode 100644 (file)
index 0000000..0fc20a2
--- /dev/null
@@ -0,0 +1,970 @@
+/*
+ * arch/arm/mach-at91/at572d940hf_devices.c
+ *
+ * Copyright (C) 2008 Atmel Antonio R. Costa <costa.antonior@gmail.com>
+ * Copyright (C) 2005 Thibaut VARENE <varenet@parisc-linux.org>
+ * Copyright (C) 2005 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/at572d940hf.h>
+#include <mach/at572d940hf_matrix.h>
+#include <mach/at91sam9_smc.h>
+
+#include "generic.h"
+#include "sam9_smc.h"
+
+
+/* --------------------------------------------------------------------
+ *  USB Host
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+static u64 ohci_dmamask = DMA_BIT_MASK(32);
+static struct at91_usbh_data usbh_data;
+
+static struct resource usbh_resources[] = {
+       [0] = {
+               .start  = AT572D940HF_UHP_BASE,
+               .end    = AT572D940HF_UHP_BASE + SZ_1M - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AT572D940HF_ID_UHP,
+               .end    = AT572D940HF_ID_UHP,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device at572d940hf_usbh_device = {
+       .name           = "at91_ohci",
+       .id             = -1,
+       .dev            = {
+                               .dma_mask               = &ohci_dmamask,
+                               .coherent_dma_mask      = DMA_BIT_MASK(32),
+                               .platform_data          = &usbh_data,
+       },
+       .resource       = usbh_resources,
+       .num_resources  = ARRAY_SIZE(usbh_resources),
+};
+
+void __init at91_add_device_usbh(struct at91_usbh_data *data)
+{
+       if (!data)
+               return;
+
+       usbh_data = *data;
+       platform_device_register(&at572d940hf_usbh_device);
+
+}
+#else
+void __init at91_add_device_usbh(struct at91_usbh_data *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  USB Device (Gadget)
+ * -------------------------------------------------------------------- */
+
+#ifdef CONFIG_USB_GADGET_AT91
+static struct at91_udc_data udc_data;
+
+static struct resource udc_resources[] = {
+       [0] = {
+               .start  = AT572D940HF_BASE_UDP,
+               .end    = AT572D940HF_BASE_UDP + SZ_16K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AT572D940HF_ID_UDP,
+               .end    = AT572D940HF_ID_UDP,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device at572d940hf_udc_device = {
+       .name           = "at91_udc",
+       .id             = -1,
+       .dev            = {
+                               .platform_data          = &udc_data,
+       },
+       .resource       = udc_resources,
+       .num_resources  = ARRAY_SIZE(udc_resources),
+};
+
+void __init at91_add_device_udc(struct at91_udc_data *data)
+{
+       if (!data)
+               return;
+
+       if (data->vbus_pin) {
+               at91_set_gpio_input(data->vbus_pin, 0);
+               at91_set_deglitch(data->vbus_pin, 1);
+       }
+
+       /* Pullup pin is handled internally */
+
+       udc_data = *data;
+       platform_device_register(&at572d940hf_udc_device);
+}
+#else
+void __init at91_add_device_udc(struct at91_udc_data *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  Ethernet
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_MACB) || defined(CONFIG_MACB_MODULE)
+static u64 eth_dmamask = DMA_BIT_MASK(32);
+static struct at91_eth_data eth_data;
+
+static struct resource eth_resources[] = {
+       [0] = {
+               .start  = AT572D940HF_BASE_EMAC,
+               .end    = AT572D940HF_BASE_EMAC + SZ_16K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AT572D940HF_ID_EMAC,
+               .end    = AT572D940HF_ID_EMAC,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device at572d940hf_eth_device = {
+       .name           = "macb",
+       .id             = -1,
+       .dev            = {
+                       .dma_mask               = &eth_dmamask,
+                       .coherent_dma_mask      = DMA_BIT_MASK(32),
+                       .platform_data          = &eth_data,
+       },
+       .resource       = eth_resources,
+       .num_resources  = ARRAY_SIZE(eth_resources),
+};
+
+void __init at91_add_device_eth(struct at91_eth_data *data)
+{
+       if (!data)
+               return;
+
+       if (data->phy_irq_pin) {
+               at91_set_gpio_input(data->phy_irq_pin, 0);
+               at91_set_deglitch(data->phy_irq_pin, 1);
+       }
+
+       /* Only RMII is supported */
+       data->is_rmii = 1;
+
+       /* Pins used for RMII */
+       at91_set_A_periph(AT91_PIN_PA16, 0);    /* ETXCK_EREFCK */
+       at91_set_A_periph(AT91_PIN_PA17, 0);    /* ERXDV */
+       at91_set_A_periph(AT91_PIN_PA18, 0);    /* ERX0 */
+       at91_set_A_periph(AT91_PIN_PA19, 0);    /* ERX1 */
+       at91_set_A_periph(AT91_PIN_PA20, 0);    /* ERXER */
+       at91_set_A_periph(AT91_PIN_PA23, 0);    /* ETXEN */
+       at91_set_A_periph(AT91_PIN_PA21, 0);    /* ETX0 */
+       at91_set_A_periph(AT91_PIN_PA22, 0);    /* ETX1 */
+       at91_set_A_periph(AT91_PIN_PA13, 0);    /* EMDIO */
+       at91_set_A_periph(AT91_PIN_PA14, 0);    /* EMDC */
+
+       eth_data = *data;
+       platform_device_register(&at572d940hf_eth_device);
+}
+#else
+void __init at91_add_device_eth(struct at91_eth_data *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  MMC / SD
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
+static u64 mmc_dmamask = DMA_BIT_MASK(32);
+static struct at91_mmc_data mmc_data;
+
+static struct resource mmc_resources[] = {
+       [0] = {
+               .start  = AT572D940HF_BASE_MCI,
+               .end    = AT572D940HF_BASE_MCI + SZ_16K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AT572D940HF_ID_MCI,
+               .end    = AT572D940HF_ID_MCI,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device at572d940hf_mmc_device = {
+       .name           = "at91_mci",
+       .id             = -1,
+       .dev            = {
+                               .dma_mask               = &mmc_dmamask,
+                               .coherent_dma_mask      = DMA_BIT_MASK(32),
+                               .platform_data          = &mmc_data,
+       },
+       .resource       = mmc_resources,
+       .num_resources  = ARRAY_SIZE(mmc_resources),
+};
+
+void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
+{
+       if (!data)
+               return;
+
+       /* input/irq */
+       if (data->det_pin) {
+               at91_set_gpio_input(data->det_pin, 1);
+               at91_set_deglitch(data->det_pin, 1);
+       }
+       if (data->wp_pin)
+               at91_set_gpio_input(data->wp_pin, 1);
+       if (data->vcc_pin)
+               at91_set_gpio_output(data->vcc_pin, 0);
+
+       /* CLK */
+       at91_set_A_periph(AT91_PIN_PC22, 0);
+
+       /* CMD */
+       at91_set_A_periph(AT91_PIN_PC23, 1);
+
+       /* DAT0, maybe DAT1..DAT3 */
+       at91_set_A_periph(AT91_PIN_PC24, 1);
+       if (data->wire4) {
+               at91_set_A_periph(AT91_PIN_PC25, 1);
+               at91_set_A_periph(AT91_PIN_PC26, 1);
+               at91_set_A_periph(AT91_PIN_PC27, 1);
+       }
+
+       mmc_data = *data;
+       platform_device_register(&at572d940hf_mmc_device);
+}
+#else
+void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  NAND / SmartMedia
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_MTD_NAND_ATMEL) || defined(CONFIG_MTD_NAND_ATMEL_MODULE)
+static struct atmel_nand_data nand_data;
+
+#define NAND_BASE      AT91_CHIPSELECT_3
+
+static struct resource nand_resources[] = {
+       {
+               .start  = NAND_BASE,
+               .end    = NAND_BASE + SZ_256M - 1,
+               .flags  = IORESOURCE_MEM,
+       }
+};
+
+static struct platform_device at572d940hf_nand_device = {
+       .name           = "atmel_nand",
+       .id             = -1,
+       .dev            = {
+                               .platform_data  = &nand_data,
+       },
+       .resource       = nand_resources,
+       .num_resources  = ARRAY_SIZE(nand_resources),
+};
+
+void __init at91_add_device_nand(struct atmel_nand_data *data)
+{
+       unsigned long csa;
+
+       if (!data)
+               return;
+
+       csa = at91_sys_read(AT91_MATRIX_EBICSA);
+       at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC_SMARTMEDIA);
+
+       /* enable pin */
+       if (data->enable_pin)
+               at91_set_gpio_output(data->enable_pin, 1);
+
+       /* ready/busy pin */
+       if (data->rdy_pin)
+               at91_set_gpio_input(data->rdy_pin, 1);
+
+       /* card detect pin */
+       if (data->det_pin)
+               at91_set_gpio_input(data->det_pin, 1);
+
+       at91_set_A_periph(AT91_PIN_PB28, 0);            /* A[22] */
+       at91_set_B_periph(AT91_PIN_PA28, 0);            /* NANDOE */
+       at91_set_B_periph(AT91_PIN_PA29, 0);            /* NANDWE */
+
+       nand_data = *data;
+       platform_device_register(&at572d940hf_nand_device);
+}
+
+#else
+void __init at91_add_device_nand(struct atmel_nand_data *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  TWI (i2c)
+ * -------------------------------------------------------------------- */
+
+/*
+ * Prefer the GPIO code since the TWI controller isn't robust
+ * (gets overruns and underruns under load) and can only issue
+ * repeated STARTs in one scenario (the driver doesn't yet handle them).
+ */
+
+#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
+
+static struct i2c_gpio_platform_data pdata = {
+       .sda_pin                = AT91_PIN_PC7,
+       .sda_is_open_drain      = 1,
+       .scl_pin                = AT91_PIN_PC8,
+       .scl_is_open_drain      = 1,
+       .udelay                 = 2,            /* ~100 kHz */
+};
+
+static struct platform_device at572d940hf_twi_device {
+       .name                   = "i2c-gpio",
+       .id                     = -1,
+       .dev.platform_data      = &pdata,
+};
+
+void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
+{
+       at91_set_GPIO_periph(AT91_PIN_PC7, 1);          /* TWD (SDA) */
+       at91_set_multi_drive(AT91_PIN_PC7, 1);
+
+       at91_set_GPIO_periph(AT91_PIN_PA8, 1);          /* TWCK (SCL) */
+       at91_set_multi_drive(AT91_PIN_PC8, 1);
+
+       i2c_register_board_info(0, devices, nr_devices);
+       platform_device_register(&at572d940hf_twi_device);
+}
+
+#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
+
+static struct resource twi0_resources[] = {
+       [0] = {
+               .start  = AT572D940HF_BASE_TWI0,
+               .end    = AT572D940HF_BASE_TWI0 + SZ_16K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AT572D940HF_ID_TWI0,
+               .end    = AT572D940HF_ID_TWI0,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device at572d940hf_twi0_device = {
+       .name           = "at91_i2c",
+       .id             = 0,
+       .resource       = twi0_resources,
+       .num_resources  = ARRAY_SIZE(twi0_resources),
+};
+
+static struct resource twi1_resources[] = {
+       [0] = {
+               .start  = AT572D940HF_BASE_TWI1,
+               .end    = AT572D940HF_BASE_TWI1 + SZ_16K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AT572D940HF_ID_TWI1,
+               .end    = AT572D940HF_ID_TWI1,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device at572d940hf_twi1_device = {
+       .name           = "at91_i2c",
+       .id             = 1,
+       .resource       = twi1_resources,
+       .num_resources  = ARRAY_SIZE(twi1_resources),
+};
+
+void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
+{
+       /* pins used for TWI0 interface */
+       at91_set_A_periph(AT91_PIN_PC7, 0);             /* TWD */
+       at91_set_multi_drive(AT91_PIN_PC7, 1);
+
+       at91_set_A_periph(AT91_PIN_PC8, 0);             /* TWCK */
+       at91_set_multi_drive(AT91_PIN_PC8, 1);
+
+       /* pins used for TWI1 interface */
+       at91_set_A_periph(AT91_PIN_PC20, 0);            /* TWD */
+       at91_set_multi_drive(AT91_PIN_PC20, 1);
+
+       at91_set_A_periph(AT91_PIN_PC21, 0);            /* TWCK */
+       at91_set_multi_drive(AT91_PIN_PC21, 1);
+
+       i2c_register_board_info(0, devices, nr_devices);
+       platform_device_register(&at572d940hf_twi0_device);
+       platform_device_register(&at572d940hf_twi1_device);
+}
+#else
+void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  SPI
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
+static u64 spi_dmamask = DMA_BIT_MASK(32);
+
+static struct resource spi0_resources[] = {
+       [0] = {
+               .start  = AT572D940HF_BASE_SPI0,
+               .end    = AT572D940HF_BASE_SPI0 + SZ_16K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AT572D940HF_ID_SPI0,
+               .end    = AT572D940HF_ID_SPI0,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device at572d940hf_spi0_device = {
+       .name           = "atmel_spi",
+       .id             = 0,
+       .dev            = {
+                               .dma_mask               = &spi_dmamask,
+                               .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+       .resource       = spi0_resources,
+       .num_resources  = ARRAY_SIZE(spi0_resources),
+};
+
+static const unsigned spi0_standard_cs[4] = { AT91_PIN_PA3, AT91_PIN_PA4, AT91_PIN_PA5, AT91_PIN_PA6 };
+
+static struct resource spi1_resources[] = {
+       [0] = {
+               .start  = AT572D940HF_BASE_SPI1,
+               .end    = AT572D940HF_BASE_SPI1 + SZ_16K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AT572D940HF_ID_SPI1,
+               .end    = AT572D940HF_ID_SPI1,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device at572d940hf_spi1_device = {
+       .name           = "atmel_spi",
+       .id             = 1,
+       .dev            = {
+                               .dma_mask               = &spi_dmamask,
+                               .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+       .resource       = spi1_resources,
+       .num_resources  = ARRAY_SIZE(spi1_resources),
+};
+
+static const unsigned spi1_standard_cs[4] = { AT91_PIN_PC3, AT91_PIN_PC4, AT91_PIN_PC5, AT91_PIN_PC6 };
+
+void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
+{
+       int i;
+       unsigned long cs_pin;
+       short enable_spi0 = 0;
+       short enable_spi1 = 0;
+
+       /* Choose SPI chip-selects */
+       for (i = 0; i < nr_devices; i++) {
+               if (devices[i].controller_data)
+                       cs_pin = (unsigned long) devices[i].controller_data;
+               else if (devices[i].bus_num == 0)
+                       cs_pin = spi0_standard_cs[devices[i].chip_select];
+               else
+                       cs_pin = spi1_standard_cs[devices[i].chip_select];
+
+               if (devices[i].bus_num == 0)
+                       enable_spi0 = 1;
+               else
+                       enable_spi1 = 1;
+
+               /* enable chip-select pin */
+               at91_set_gpio_output(cs_pin, 1);
+
+               /* pass chip-select pin to driver */
+               devices[i].controller_data = (void *) cs_pin;
+       }
+
+       spi_register_board_info(devices, nr_devices);
+
+       /* Configure SPI bus(es) */
+       if (enable_spi0) {
+               at91_set_A_periph(AT91_PIN_PA0, 0);     /* SPI0_MISO */
+               at91_set_A_periph(AT91_PIN_PA1, 0);     /* SPI0_MOSI */
+               at91_set_A_periph(AT91_PIN_PA2, 0);     /* SPI0_SPCK */
+
+               at91_clock_associate("spi0_clk", &at572d940hf_spi0_device.dev, "spi_clk");
+               platform_device_register(&at572d940hf_spi0_device);
+       }
+       if (enable_spi1) {
+               at91_set_A_periph(AT91_PIN_PC0, 0);     /* SPI1_MISO */
+               at91_set_A_periph(AT91_PIN_PC1, 0);     /* SPI1_MOSI */
+               at91_set_A_periph(AT91_PIN_PC2, 0);     /* SPI1_SPCK */
+
+               at91_clock_associate("spi1_clk", &at572d940hf_spi1_device.dev, "spi_clk");
+               platform_device_register(&at572d940hf_spi1_device);
+       }
+}
+#else
+void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  Timer/Counter blocks
+ * -------------------------------------------------------------------- */
+
+#ifdef CONFIG_ATMEL_TCLIB
+
+static struct resource tcb_resources[] = {
+       [0] = {
+               .start  = AT572D940HF_BASE_TCB,
+               .end    = AT572D940HF_BASE_TCB + SZ_16K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AT572D940HF_ID_TC0,
+               .end    = AT572D940HF_ID_TC0,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = AT572D940HF_ID_TC1,
+               .end    = AT572D940HF_ID_TC1,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [3] = {
+               .start  = AT572D940HF_ID_TC2,
+               .end    = AT572D940HF_ID_TC2,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device at572d940hf_tcb_device = {
+       .name           = "atmel_tcb",
+       .id             = 0,
+       .resource       = tcb_resources,
+       .num_resources  = ARRAY_SIZE(tcb_resources),
+};
+
+static void __init at91_add_device_tc(void)
+{
+       /* this chip has a separate clock and irq for each TC channel */
+       at91_clock_associate("tc0_clk", &at572d940hf_tcb_device.dev, "t0_clk");
+       at91_clock_associate("tc1_clk", &at572d940hf_tcb_device.dev, "t1_clk");
+       at91_clock_associate("tc2_clk", &at572d940hf_tcb_device.dev, "t2_clk");
+       platform_device_register(&at572d940hf_tcb_device);
+}
+#else
+static void __init at91_add_device_tc(void) { }
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  RTT
+ * -------------------------------------------------------------------- */
+
+static struct resource rtt_resources[] = {
+       {
+               .start  = AT91_BASE_SYS + AT91_RTT,
+               .end    = AT91_BASE_SYS + AT91_RTT + SZ_16 - 1,
+               .flags  = IORESOURCE_MEM,
+       }
+};
+
+static struct platform_device at572d940hf_rtt_device = {
+       .name           = "at91_rtt",
+       .id             = 0,
+       .resource       = rtt_resources,
+       .num_resources  = ARRAY_SIZE(rtt_resources),
+};
+
+static void __init at91_add_device_rtt(void)
+{
+       platform_device_register(&at572d940hf_rtt_device);
+}
+
+
+/* --------------------------------------------------------------------
+ *  Watchdog
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_AT91SAM9X_WATCHDOG) || defined(CONFIG_AT91SAM9X_WATCHDOG_MODULE)
+static struct platform_device at572d940hf_wdt_device = {
+       .name           = "at91_wdt",
+       .id             = -1,
+       .num_resources  = 0,
+};
+
+static void __init at91_add_device_watchdog(void)
+{
+       platform_device_register(&at572d940hf_wdt_device);
+}
+#else
+static void __init at91_add_device_watchdog(void) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  UART
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_SERIAL_ATMEL)
+static struct resource dbgu_resources[] = {
+       [0] = {
+               .start  = AT91_VA_BASE_SYS + AT91_DBGU,
+               .end    = AT91_VA_BASE_SYS + AT91_DBGU + SZ_512 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AT91_ID_SYS,
+               .end    = AT91_ID_SYS,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct atmel_uart_data dbgu_data = {
+       .use_dma_tx     = 0,
+       .use_dma_rx     = 0,            /* DBGU not capable of receive DMA */
+       .regs           = (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
+};
+
+static u64 dbgu_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device at572d940hf_dbgu_device = {
+       .name           = "atmel_usart",
+       .id             = 0,
+       .dev            = {
+                               .dma_mask               = &dbgu_dmamask,
+                               .coherent_dma_mask      = DMA_BIT_MASK(32),
+                               .platform_data          = &dbgu_data,
+       },
+       .resource       = dbgu_resources,
+       .num_resources  = ARRAY_SIZE(dbgu_resources),
+};
+
+static inline void configure_dbgu_pins(void)
+{
+       at91_set_A_periph(AT91_PIN_PC31, 1);            /* DTXD */
+       at91_set_A_periph(AT91_PIN_PC30, 0);            /* DRXD */
+}
+
+static struct resource uart0_resources[] = {
+       [0] = {
+               .start  = AT572D940HF_BASE_US0,
+               .end    = AT572D940HF_BASE_US0 + SZ_16K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AT572D940HF_ID_US0,
+               .end    = AT572D940HF_ID_US0,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct atmel_uart_data uart0_data = {
+       .use_dma_tx     = 1,
+       .use_dma_rx     = 1,
+};
+
+static u64 uart0_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device at572d940hf_uart0_device = {
+       .name           = "atmel_usart",
+       .id             = 1,
+       .dev            = {
+                               .dma_mask               = &uart0_dmamask,
+                               .coherent_dma_mask      = DMA_BIT_MASK(32),
+                               .platform_data          = &uart0_data,
+       },
+       .resource       = uart0_resources,
+       .num_resources  = ARRAY_SIZE(uart0_resources),
+};
+
+static inline void configure_usart0_pins(unsigned pins)
+{
+       at91_set_A_periph(AT91_PIN_PA8, 1);             /* TXD0 */
+       at91_set_A_periph(AT91_PIN_PA7, 0);             /* RXD0 */
+
+       if (pins & ATMEL_UART_RTS)
+               at91_set_A_periph(AT91_PIN_PA10, 0);    /* RTS0 */
+       if (pins & ATMEL_UART_CTS)
+               at91_set_A_periph(AT91_PIN_PA9, 0);     /* CTS0 */
+}
+
+static struct resource uart1_resources[] = {
+       [0] = {
+               .start  = AT572D940HF_BASE_US1,
+               .end    = AT572D940HF_BASE_US1 + SZ_16K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AT572D940HF_ID_US1,
+               .end    = AT572D940HF_ID_US1,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct atmel_uart_data uart1_data = {
+       .use_dma_tx     = 1,
+       .use_dma_rx     = 1,
+};
+
+static u64 uart1_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device at572d940hf_uart1_device = {
+       .name           = "atmel_usart",
+       .id             = 2,
+       .dev            = {
+                               .dma_mask               = &uart1_dmamask,
+                               .coherent_dma_mask      = DMA_BIT_MASK(32),
+                               .platform_data          = &uart1_data,
+       },
+       .resource       = uart1_resources,
+       .num_resources  = ARRAY_SIZE(uart1_resources),
+};
+
+static inline void configure_usart1_pins(unsigned pins)
+{
+       at91_set_A_periph(AT91_PIN_PC10, 1);            /* TXD1 */
+       at91_set_A_periph(AT91_PIN_PC9 , 0);            /* RXD1 */
+
+       if (pins & ATMEL_UART_RTS)
+               at91_set_A_periph(AT91_PIN_PC12, 0);    /* RTS1 */
+       if (pins & ATMEL_UART_CTS)
+               at91_set_A_periph(AT91_PIN_PC11, 0);    /* CTS1 */
+}
+
+static struct resource uart2_resources[] = {
+       [0] = {
+               .start  = AT572D940HF_BASE_US2,
+               .end    = AT572D940HF_BASE_US2 + SZ_16K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AT572D940HF_ID_US2,
+               .end    = AT572D940HF_ID_US2,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct atmel_uart_data uart2_data = {
+       .use_dma_tx     = 1,
+       .use_dma_rx     = 1,
+};
+
+static u64 uart2_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device at572d940hf_uart2_device = {
+       .name           = "atmel_usart",
+       .id             = 3,
+       .dev            = {
+                               .dma_mask               = &uart2_dmamask,
+                               .coherent_dma_mask      = DMA_BIT_MASK(32),
+                               .platform_data          = &uart2_data,
+       },
+       .resource       = uart2_resources,
+       .num_resources  = ARRAY_SIZE(uart2_resources),
+};
+
+static inline void configure_usart2_pins(unsigned pins)
+{
+       at91_set_A_periph(AT91_PIN_PC15, 1);            /* TXD2 */
+       at91_set_A_periph(AT91_PIN_PC14, 0);            /* RXD2 */
+
+       if (pins & ATMEL_UART_RTS)
+               at91_set_A_periph(AT91_PIN_PC17, 0);    /* RTS2 */
+       if (pins & ATMEL_UART_CTS)
+               at91_set_A_periph(AT91_PIN_PC16, 0);    /* CTS2 */
+}
+
+static struct platform_device *__initdata at91_uarts[ATMEL_MAX_UART];  /* the UARTs to use */
+struct platform_device *atmel_default_console_device;  /* the serial console device */
+
+void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
+{
+       struct platform_device *pdev;
+
+       switch (id) {
+               case 0:         /* DBGU */
+                       pdev = &at572d940hf_dbgu_device;
+                       configure_dbgu_pins();
+                       at91_clock_associate("mck", &pdev->dev, "usart");
+                       break;
+               case AT572D940HF_ID_US0:
+                       pdev = &at572d940hf_uart0_device;
+                       configure_usart0_pins(pins);
+                       at91_clock_associate("usart0_clk", &pdev->dev, "usart");
+                       break;
+               case AT572D940HF_ID_US1:
+                       pdev = &at572d940hf_uart1_device;
+                       configure_usart1_pins(pins);
+                       at91_clock_associate("usart1_clk", &pdev->dev, "usart");
+                       break;
+               case AT572D940HF_ID_US2:
+                       pdev = &at572d940hf_uart2_device;
+                       configure_usart2_pins(pins);
+                       at91_clock_associate("usart2_clk", &pdev->dev, "usart");
+                       break;
+               default:
+                       return;
+       }
+       pdev->id = portnr;              /* update to mapped ID */
+
+       if (portnr < ATMEL_MAX_UART)
+               at91_uarts[portnr] = pdev;
+}
+
+void __init at91_set_serial_console(unsigned portnr)
+{
+       if (portnr < ATMEL_MAX_UART)
+               atmel_default_console_device = at91_uarts[portnr];
+}
+
+void __init at91_add_device_serial(void)
+{
+       int i;
+
+       for (i = 0; i < ATMEL_MAX_UART; i++) {
+               if (at91_uarts[i])
+                       platform_device_register(at91_uarts[i]);
+       }
+
+       if (!atmel_default_console_device)
+               printk(KERN_INFO "AT91: No default serial console defined.\n");
+}
+
+#else
+void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
+void __init at91_set_serial_console(unsigned portnr) {}
+void __init at91_add_device_serial(void) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  mAgic
+ * -------------------------------------------------------------------- */
+
+#ifdef CONFIG_MAGICV
+static struct resource mAgic_resources[] = {
+       {
+               .start = AT91_MAGIC_PM_BASE,
+               .end   = AT91_MAGIC_PM_BASE + AT91_MAGIC_PM_SIZE - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = AT91_MAGIC_DM_I_BASE,
+               .end   = AT91_MAGIC_DM_I_BASE + AT91_MAGIC_DM_I_SIZE - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = AT91_MAGIC_DM_F_BASE,
+               .end   = AT91_MAGIC_DM_F_BASE + AT91_MAGIC_DM_F_SIZE - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = AT91_MAGIC_DM_DB_BASE,
+               .end   = AT91_MAGIC_DM_DB_BASE + AT91_MAGIC_DM_DB_SIZE - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = AT91_MAGIC_REGS_BASE,
+               .end   = AT91_MAGIC_REGS_BASE + AT91_MAGIC_REGS_SIZE - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = AT91_MAGIC_EXTPAGE_BASE,
+               .end   = AT91_MAGIC_EXTPAGE_BASE + AT91_MAGIC_EXTPAGE_SIZE - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start  = AT572D940HF_ID_MSIRQ0,
+               .end    = AT572D940HF_ID_MSIRQ0,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .start  = AT572D940HF_ID_MHALT,
+               .end    = AT572D940HF_ID_MHALT,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .start  = AT572D940HF_ID_MEXC,
+               .end    = AT572D940HF_ID_MEXC,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .start  = AT572D940HF_ID_MEDMA,
+               .end    = AT572D940HF_ID_MEDMA,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mAgic_device = {
+       .name           = "mAgic",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(mAgic_resources),
+       .resource       = mAgic_resources,
+};
+
+void __init at91_add_device_mAgic(void)
+{
+       platform_device_register(&mAgic_device);
+}
+#else
+void __init at91_add_device_mAgic(void) {}
+#endif
+
+
+/* -------------------------------------------------------------------- */
+
+/*
+ * These devices are always present and don't need any board-specific
+ * setup.
+ */
+static int __init at91_add_standard_devices(void)
+{
+       at91_add_device_rtt();
+       at91_add_device_watchdog();
+       at91_add_device_tc();
+       return 0;
+}
+
+arch_initcall(at91_add_standard_devices);
diff --git a/arch/arm/mach-at91/board-at572d940hf_ek.c b/arch/arm/mach-at91/board-at572d940hf_ek.c
new file mode 100644 (file)
index 0000000..5daff27
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * linux/arch/arm/mach-at91/board-at572d940hf_ek.c
+ *
+ * Copyright (C) 2008 Atmel Antonio R. Costa <costa.antonior@gmail.com>
+ * Copyright (C) 2005 SAN People
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ds1305.h>
+#include <linux/irq.h>
+#include <linux/mtd/physmap.h>
+
+#include <mach/hardware.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/at91sam9_smc.h>
+
+#include "sam9_smc.h"
+#include "generic.h"
+
+
+static void __init eb_map_io(void)
+{
+       /* Initialize processor: 12.500 MHz crystal */
+       at572d940hf_initialize(12000000);
+
+       /* DBGU on ttyS0. (Rx & Tx only) */
+       at91_register_uart(0, 0, 0);
+
+       /* USART0 on ttyS1. (Rx & Tx only) */
+       at91_register_uart(AT572D940HF_ID_US0, 1, 0);
+
+       /* USART1 on ttyS2. (Rx & Tx only) */
+       at91_register_uart(AT572D940HF_ID_US1, 2, 0);
+
+       /* USART2 on ttyS3. (Tx & Rx only */
+       at91_register_uart(AT572D940HF_ID_US2, 3, 0);
+
+       /* set serial console to ttyS0 (ie, DBGU) */
+       at91_set_serial_console(0);
+}
+
+static void __init eb_init_irq(void)
+{
+       at572d940hf_init_interrupts(NULL);
+}
+
+
+/*
+ * USB Host Port
+ */
+static struct at91_usbh_data __initdata eb_usbh_data = {
+       .ports          = 2,
+};
+
+
+/*
+ * USB Device Port
+ */
+static struct at91_udc_data __initdata eb_udc_data = {
+       .vbus_pin       = 0,            /* no VBUS detection,UDC always on */
+       .pullup_pin     = 0,            /* pull-up driven by UDC */
+};
+
+
+/*
+ * MCI (SD/MMC)
+ */
+static struct at91_mmc_data __initdata eb_mmc_data = {
+       .wire4          = 1,
+/*     .det_pin        = ... not connected */
+/*     .wp_pin         = ... not connected */
+/*     .vcc_pin        = ... not connected */
+};
+
+
+/*
+ * MACB Ethernet device
+ */
+static struct at91_eth_data __initdata eb_eth_data = {
+       .phy_irq_pin    = AT91_PIN_PB25,
+       .is_rmii        = 1,
+};
+
+/*
+ * NOR flash
+ */
+
+static struct mtd_partition eb_nor_partitions[] = {
+       {
+               .name           = "Raw Environment",
+               .offset         = 0,
+               .size           = SZ_4M,
+               .mask_flags     = 0,
+       },
+       {
+               .name           = "OS FS",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 3 * SZ_1M,
+               .mask_flags     = 0,
+       },
+       {
+               .name           = "APP FS",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = MTDPART_SIZ_FULL,
+               .mask_flags     = 0,
+       },
+};
+
+static void nor_flash_set_vpp(struct map_info* mi, int i) {
+};
+
+static struct physmap_flash_data nor_flash_data = {
+       .width          = 4,
+       .parts          = eb_nor_partitions,
+       .nr_parts       = ARRAY_SIZE(eb_nor_partitions),
+       .set_vpp        = nor_flash_set_vpp,
+};
+
+static struct resource nor_flash_resources[] = {
+       {
+               .start  = AT91_CHIPSELECT_0,
+               .end    = AT91_CHIPSELECT_0 + SZ_16M - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device nor_flash = {
+       .name           = "physmap-flash",
+       .id             = 0,
+       .dev            = {
+                               .platform_data = &nor_flash_data,
+                       },
+       .resource       = nor_flash_resources,
+       .num_resources  = ARRAY_SIZE(nor_flash_resources),
+};
+
+static struct sam9_smc_config __initdata eb_nor_smc_config = {
+       .ncs_read_setup         = 1,
+       .nrd_setup              = 1,
+       .ncs_write_setup        = 1,
+       .nwe_setup              = 1,
+
+       .ncs_read_pulse         = 7,
+       .nrd_pulse              = 7,
+       .ncs_write_pulse        = 7,
+       .nwe_pulse              = 7,
+
+       .read_cycle             = 9,
+       .write_cycle            = 9,
+
+       .mode                   = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_BAT_WRITE | AT91_SMC_DBW_32,
+       .tdf_cycles             = 1,
+};
+
+static void __init eb_add_device_nor(void)
+{
+       /* configure chip-select 0 (NOR) */
+       sam9_smc_configure(0, &eb_nor_smc_config);
+       platform_device_register(&nor_flash);
+}
+
+/*
+ * NAND flash
+ */
+static struct mtd_partition __initdata eb_nand_partition[] = {
+       {
+               .name   = "Partition 1",
+               .offset = 0,
+               .size   = SZ_16M,
+       },
+       {
+               .name   = "Partition 2",
+               .offset = MTDPART_OFS_NXTBLK,
+               .size   = MTDPART_SIZ_FULL,
+       }
+};
+
+static struct mtd_partition * __init nand_partitions(int size, int *num_partitions)
+{
+       *num_partitions = ARRAY_SIZE(eb_nand_partition);
+       return eb_nand_partition;
+}
+
+static struct atmel_nand_data __initdata eb_nand_data = {
+       .ale            = 22,
+       .cle            = 21,
+/*     .det_pin        = ... not connected */
+/*     .rdy_pin        = AT91_PIN_PC16, */
+       .enable_pin     = AT91_PIN_PA15,
+       .partition_info = nand_partitions,
+#if defined(CONFIG_MTD_NAND_AT91_BUSWIDTH_16)
+       .bus_width_16   = 1,
+#else
+       .bus_width_16   = 0,
+#endif
+};
+
+static struct sam9_smc_config __initdata eb_nand_smc_config = {
+       .ncs_read_setup         = 0,
+       .nrd_setup              = 0,
+       .ncs_write_setup        = 1,
+       .nwe_setup              = 1,
+
+       .ncs_read_pulse         = 3,
+       .nrd_pulse              = 3,
+       .ncs_write_pulse        = 3,
+       .nwe_pulse              = 3,
+
+       .read_cycle             = 5,
+       .write_cycle            = 5,
+
+       .mode                   = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE,
+       .tdf_cycles             = 12,
+};
+
+static void __init eb_add_device_nand(void)
+{
+       /* setup bus-width (8 or 16) */
+       if (eb_nand_data.bus_width_16)
+               eb_nand_smc_config.mode |= AT91_SMC_DBW_16;
+       else
+               eb_nand_smc_config.mode |= AT91_SMC_DBW_8;
+
+       /* configure chip-select 3 (NAND) */
+       sam9_smc_configure(3, &eb_nand_smc_config);
+
+       at91_add_device_nand(&eb_nand_data);
+}
+
+
+/*
+ * SPI devices
+ */
+static struct resource rtc_resources[] = {
+       [0] = {
+               .start  = AT572D940HF_ID_IRQ1,
+               .end    = AT572D940HF_ID_IRQ1,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct ds1305_platform_data ds1306_data = {
+       .is_ds1306      = true,
+       .en_1hz         = false,
+};
+
+static struct spi_board_info eb_spi_devices[] = {
+       {       /* RTC Dallas DS1306 */
+               .modalias       = "rtc-ds1305",
+               .chip_select    = 3,
+               .mode           = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA,
+               .max_speed_hz   = 500000,
+               .bus_num        = 0,
+               .irq            = AT572D940HF_ID_IRQ1,
+               .platform_data  = (void *) &ds1306_data,
+       },
+#if defined(CONFIG_MTD_AT91_DATAFLASH_CARD)
+       {       /* Dataflash card */
+               .modalias       = "mtd_dataflash",
+               .chip_select    = 0,
+               .max_speed_hz   = 15 * 1000 * 1000,
+               .bus_num        = 0,
+       },
+#endif
+};
+
+static void __init eb_board_init(void)
+{
+       /* Serial */
+       at91_add_device_serial();
+       /* USB Host */
+       at91_add_device_usbh(&eb_usbh_data);
+       /* USB Device */
+       at91_add_device_udc(&eb_udc_data);
+       /* I2C */
+       at91_add_device_i2c(NULL, 0);
+       /* NOR */
+       eb_add_device_nor();
+       /* NAND */
+       eb_add_device_nand();
+       /* SPI */
+       at91_add_device_spi(eb_spi_devices, ARRAY_SIZE(eb_spi_devices));
+       /* MMC */
+       at91_add_device_mmc(0, &eb_mmc_data);
+       /* Ethernet */
+       at91_add_device_eth(&eb_eth_data);
+       /* mAgic */
+       at91_add_device_mAgic();
+}
+
+MACHINE_START(AT572D940HFEB, "Atmel AT91D940HF-EB")
+       /* Maintainer: Atmel <costa.antonior@gmail.com> */
+       .phys_io        = AT91_BASE_SYS,
+       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
+       .boot_params    = AT91_SDRAM_BASE + 0x100,
+       .timer          = &at91sam926x_timer,
+       .map_io         = eb_map_io,
+       .init_irq       = eb_init_irq,
+       .init_machine   = eb_board_init,
+MACHINE_END
index c042dcf4725fc8ec3166cb9ddc7436109f1fca6c..7f7da439341fabc4e85b6febeb8b1f3e2cd6f4ee 100644 (file)
@@ -29,6 +29,7 @@
 #include <mach/cpu.h>
 
 #include "clock.h"
+#include "generic.h"
 
 
 /*
@@ -628,7 +629,7 @@ static void __init at91_pllb_usbfs_clock_init(unsigned long main_clock)
                at91_sys_write(AT91_PMC_SCER, AT91RM9200_PMC_MCKUDP);
        } else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() ||
                   cpu_is_at91sam9263() || cpu_is_at91sam9g20() ||
-                  cpu_is_at91sam9g10()) {
+                  cpu_is_at91sam9g10() || cpu_is_at572d940hf()) {
                uhpck.pmc_mask = AT91SAM926x_PMC_UHP;
                udpck.pmc_mask = AT91SAM926x_PMC_UDP;
        } else if (cpu_is_at91cap9()) {
@@ -711,12 +712,13 @@ int __init at91_clock_init(unsigned long main_clock)
        /*
         * USB HS clock init
         */
-       if (cpu_has_utmi())
+       if (cpu_has_utmi()) {
                /*
                 * multiplier is hard-wired to 40
                 * (obtain the USB High Speed 480 MHz when input is 12 MHz)
                 */
                utmi_clk.rate_hz = 40 * utmi_clk.parent->rate_hz;
+       }
 
        /*
         * USB FS clock init
@@ -746,7 +748,7 @@ int __init at91_clock_init(unsigned long main_clock)
                mck.rate_hz = (mckr & AT91_PMC_MDIV) == AT91SAM9_PMC_MDIV_3 ?
                        freq / 3 : freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */
        } else {
-               mck.rate_hz = freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8));      /* mdiv */
+               mck.rate_hz = freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8));              /* mdiv */
        }
 
        /* Register the PMC's standard clocks */
index 1ba3b95ff3594f10cd30c7b433b38e0f0e497d4e..6cf4b78e175d7a47775463d03f4f6c7146a2910e 100644 (file)
@@ -22,7 +22,7 @@ struct clk {
        struct clk      *parent;
        u32             pmc_mask;
        void            (*mode)(struct clk *, int);
-       unsigned        id:2;           /* PCK0..3, or 32k/main/a/b */
+       unsigned        id:3;           /* PCK0..4, or 32k/main/a/b */
        unsigned        type;           /* clock type */
        u16             users;
 };
index 88e413b38480233f40d61bf5b8edbb1a8d46d432..65c3dc5ba0d0c608e649565121ac59e3ce4d1159 100644 (file)
@@ -17,6 +17,7 @@ extern void __init at91sam9rl_initialize(unsigned long main_clock);
 extern void __init at91sam9g45_initialize(unsigned long main_clock);
 extern void __init at91x40_initialize(unsigned long main_clock);
 extern void __init at91cap9_initialize(unsigned long main_clock);
+extern void __init at572d940hf_initialize(unsigned long main_clock);
 
  /* Interrupts */
 extern void __init at91rm9200_init_interrupts(unsigned int priority[]);
@@ -27,6 +28,7 @@ extern void __init at91sam9rl_init_interrupts(unsigned int priority[]);
 extern void __init at91sam9g45_init_interrupts(unsigned int priority[]);
 extern void __init at91x40_init_interrupts(unsigned int priority[]);
 extern void __init at91cap9_init_interrupts(unsigned int priority[]);
+extern void __init at572d940hf_init_interrupts(unsigned int priority[]);
 extern void __init at91_aic_init(unsigned int priority[]);
 
  /* Timer */
diff --git a/arch/arm/mach-at91/include/mach/at572d940hf.h b/arch/arm/mach-at91/include/mach/at572d940hf.h
new file mode 100644 (file)
index 0000000..2d9b0af
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * include/mach/at572d940hf.h
+ *
+ * Antonio R. Costa <costa.antonior@gmail.com>
+ * Copyright (C) 2008 Atmel
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 AT572D940HF_H
+#define AT572D940HF_H
+
+/*
+ * Peripheral identifiers/interrupts.
+ */
+#define AT91_ID_FIQ            0       /* Advanced Interrupt Controller (FIQ) */
+#define AT91_ID_SYS            1       /* System Peripherals */
+#define AT572D940HF_ID_PIOA    2       /* Parallel IO Controller A */
+#define AT572D940HF_ID_PIOB    3       /* Parallel IO Controller B */
+#define AT572D940HF_ID_PIOC    4       /* Parallel IO Controller C */
+#define AT572D940HF_ID_EMAC    5       /* MACB ethernet controller */
+#define AT572D940HF_ID_US0     6       /* USART 0 */
+#define AT572D940HF_ID_US1     7       /* USART 1 */
+#define AT572D940HF_ID_US2     8       /* USART 2 */
+#define AT572D940HF_ID_MCI     9       /* Multimedia Card Interface */
+#define AT572D940HF_ID_UDP     10      /* USB Device Port */
+#define AT572D940HF_ID_TWI0    11      /* Two-Wire Interface 0 */
+#define AT572D940HF_ID_SPI0    12      /* Serial Peripheral Interface 0 */
+#define AT572D940HF_ID_SPI1    13      /* Serial Peripheral Interface 1 */
+#define AT572D940HF_ID_SSC0    14      /* Serial Synchronous Controller 0 */
+#define AT572D940HF_ID_SSC1    15      /* Serial Synchronous Controller 1 */
+#define AT572D940HF_ID_SSC2    16      /* Serial Synchronous Controller 2 */
+#define AT572D940HF_ID_TC0     17      /* Timer Counter 0 */
+#define AT572D940HF_ID_TC1     18      /* Timer Counter 1 */
+#define AT572D940HF_ID_TC2     19      /* Timer Counter 2 */
+#define AT572D940HF_ID_UHP     20      /* USB Host port */
+#define AT572D940HF_ID_SSC3    21      /* Serial Synchronous Controller 3 */
+#define AT572D940HF_ID_TWI1    22      /* Two-Wire Interface 1 */
+#define AT572D940HF_ID_CAN0    23      /* CAN Controller 0 */
+#define AT572D940HF_ID_CAN1    24      /* CAN Controller 1 */
+#define AT572D940HF_ID_MHALT   25      /* mAgicV HALT line */
+#define AT572D940HF_ID_MSIRQ0  26      /* mAgicV SIRQ0 line */
+#define AT572D940HF_ID_MEXC    27      /* mAgicV exception line */
+#define AT572D940HF_ID_MEDMA   28      /* mAgicV end of DMA line */
+#define AT572D940HF_ID_IRQ0    29      /* External Interrupt Source (IRQ0) */
+#define AT572D940HF_ID_IRQ1    30      /* External Interrupt Source (IRQ1) */
+#define AT572D940HF_ID_IRQ2    31      /* External Interrupt Source (IRQ2) */
+
+
+/*
+ * User Peripheral physical base addresses.
+ */
+#define AT572D940HF_BASE_TCB   0xfffa0000
+#define AT572D940HF_BASE_TC0   0xfffa0000
+#define AT572D940HF_BASE_TC1   0xfffa0040
+#define AT572D940HF_BASE_TC2   0xfffa0080
+#define AT572D940HF_BASE_UDP   0xfffa4000
+#define AT572D940HF_BASE_MCI   0xfffa8000
+#define AT572D940HF_BASE_TWI0  0xfffac000
+#define AT572D940HF_BASE_US0   0xfffb0000
+#define AT572D940HF_BASE_US1   0xfffb4000
+#define AT572D940HF_BASE_US2   0xfffb8000
+#define AT572D940HF_BASE_SSC0  0xfffbc000
+#define AT572D940HF_BASE_SSC1  0xfffc0000
+#define AT572D940HF_BASE_SSC2  0xfffc4000
+#define AT572D940HF_BASE_SPI0  0xfffc8000
+#define AT572D940HF_BASE_SPI1  0xfffcc000
+#define AT572D940HF_BASE_SSC3  0xfffd0000
+#define AT572D940HF_BASE_TWI1  0xfffd4000
+#define AT572D940HF_BASE_EMAC  0xfffd8000
+#define AT572D940HF_BASE_CAN0  0xfffdc000
+#define AT572D940HF_BASE_CAN1  0xfffe0000
+#define AT91_BASE_SYS          0xffffea00
+
+
+/*
+ * System Peripherals (offset from AT91_BASE_SYS)
+ */
+#define AT91_SDRAMC    (0xffffea00 - AT91_BASE_SYS)
+#define AT91_SMC       (0xffffec00 - AT91_BASE_SYS)
+#define AT91_MATRIX    (0xffffee00 - AT91_BASE_SYS)
+#define AT91_AIC       (0xfffff000 - AT91_BASE_SYS)
+#define AT91_DBGU      (0xfffff200 - AT91_BASE_SYS)
+#define AT91_PIOA      (0xfffff400 - AT91_BASE_SYS)
+#define AT91_PIOB      (0xfffff600 - AT91_BASE_SYS)
+#define AT91_PIOC      (0xfffff800 - AT91_BASE_SYS)
+#define AT91_PMC       (0xfffffc00 - AT91_BASE_SYS)
+#define AT91_RSTC      (0xfffffd00 - AT91_BASE_SYS)
+#define AT91_RTT       (0xfffffd20 - AT91_BASE_SYS)
+#define AT91_PIT       (0xfffffd30 - AT91_BASE_SYS)
+#define AT91_WDT       (0xfffffd40 - AT91_BASE_SYS)
+
+#define AT91_USART0    AT572D940HF_ID_US0
+#define AT91_USART1    AT572D940HF_ID_US1
+#define AT91_USART2    AT572D940HF_ID_US2
+
+
+/*
+ * Internal Memory.
+ */
+#define AT572D940HF_SRAM_BASE  0x00300000      /* Internal SRAM base address */
+#define AT572D940HF_SRAM_SIZE  (48 * SZ_1K)    /* Internal SRAM size (48Kb) */
+
+#define AT572D940HF_ROM_BASE   0x00400000      /* Internal ROM base address */
+#define AT572D940HF_ROM_SIZE   SZ_32K          /* Internal ROM size (32Kb) */
+
+#define AT572D940HF_UHP_BASE   0x00500000      /* USB Host controller */
+
+
+#endif
diff --git a/arch/arm/mach-at91/include/mach/at572d940hf_matrix.h b/arch/arm/mach-at91/include/mach/at572d940hf_matrix.h
new file mode 100644 (file)
index 0000000..b6751df
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * include/mach//at572d940hf_matrix.h
+ *
+ * Antonio R. Costa <costa.antonior@gmail.com>
+ * Copyright (C) 2008 Atmel
+ *
+ * Copyright (C) 2005 SAN People
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef AT572D940HF_MATRIX_H
+#define AT572D940HF_MATRIX_H
+
+#define AT91_MATRIX_MCFG0      (AT91_MATRIX + 0x00)    /* Master Configuration Register 0 */
+#define AT91_MATRIX_MCFG1      (AT91_MATRIX + 0x04)    /* Master Configuration Register 1 */
+#define AT91_MATRIX_MCFG2      (AT91_MATRIX + 0x08)    /* Master Configuration Register 2 */
+#define AT91_MATRIX_MCFG3      (AT91_MATRIX + 0x0C)    /* Master Configuration Register 3 */
+#define AT91_MATRIX_MCFG4      (AT91_MATRIX + 0x10)    /* Master Configuration Register 4 */
+#define AT91_MATRIX_MCFG5      (AT91_MATRIX + 0x14)    /* Master Configuration Register 5 */
+
+#define                AT91_MATRIX_ULBT        (7 << 0)        /* Undefined Length Burst Type */
+#define                        AT91_MATRIX_ULBT_INFINITE       (0 << 0)
+#define                        AT91_MATRIX_ULBT_SINGLE         (1 << 0)
+#define                        AT91_MATRIX_ULBT_FOUR           (2 << 0)
+#define                        AT91_MATRIX_ULBT_EIGHT          (3 << 0)
+#define                        AT91_MATRIX_ULBT_SIXTEEN        (4 << 0)
+
+#define AT91_MATRIX_SCFG0      (AT91_MATRIX + 0x40)    /* Slave Configuration Register 0 */
+#define AT91_MATRIX_SCFG1      (AT91_MATRIX + 0x44)    /* Slave Configuration Register 1 */
+#define AT91_MATRIX_SCFG2      (AT91_MATRIX + 0x48)    /* Slave Configuration Register 2 */
+#define AT91_MATRIX_SCFG3      (AT91_MATRIX + 0x4C)    /* Slave Configuration Register 3 */
+#define AT91_MATRIX_SCFG4      (AT91_MATRIX + 0x50)    /* Slave Configuration Register 4 */
+#define                AT91_MATRIX_SLOT_CYCLE          (0xff << 0)     /* Maximum Number of Allowed Cycles for a Burst */
+#define                AT91_MATRIX_DEFMSTR_TYPE        (3    << 16)    /* Default Master Type */
+#define                        AT91_MATRIX_DEFMSTR_TYPE_NONE   (0 << 16)
+#define                        AT91_MATRIX_DEFMSTR_TYPE_LAST   (1 << 16)
+#define                        AT91_MATRIX_DEFMSTR_TYPE_FIXED  (2 << 16)
+#define                AT91_MATRIX_FIXED_DEFMSTR       (0x7  << 18)    /* Fixed Index of Default Master */
+#define                AT91_MATRIX_ARBT                (3    << 24)    /* Arbitration Type */
+#define                        AT91_MATRIX_ARBT_ROUND_ROBIN    (0 << 24)
+#define                        AT91_MATRIX_ARBT_FIXED_PRIORITY (1 << 24)
+
+#define AT91_MATRIX_PRAS0      (AT91_MATRIX + 0x80)    /* Priority Register A for Slave 0 */
+#define AT91_MATRIX_PRAS1      (AT91_MATRIX + 0x88)    /* Priority Register A for Slave 1 */
+#define AT91_MATRIX_PRAS2      (AT91_MATRIX + 0x90)    /* Priority Register A for Slave 2 */
+#define AT91_MATRIX_PRAS3      (AT91_MATRIX + 0x98)    /* Priority Register A for Slave 3 */
+#define AT91_MATRIX_PRAS4      (AT91_MATRIX + 0xA0)    /* Priority Register A for Slave 4 */
+
+#define                AT91_MATRIX_M0PR                (3 << 0)        /* Master 0 Priority */
+#define                AT91_MATRIX_M1PR                (3 << 4)        /* Master 1 Priority */
+#define                AT91_MATRIX_M2PR                (3 << 8)        /* Master 2 Priority */
+#define                AT91_MATRIX_M3PR                (3 << 12)       /* Master 3 Priority */
+#define                AT91_MATRIX_M4PR                (3 << 16)       /* Master 4 Priority */
+#define                AT91_MATRIX_M5PR                (3 << 20)       /* Master 5 Priority */
+#define                AT91_MATRIX_M6PR                (3 << 24)       /* Master 6 Priority */
+
+#define AT91_MATRIX_MRCR       (AT91_MATRIX + 0x100)   /* Master Remap Control Register */
+#define                AT91_MATRIX_RCB0                (1 << 0)        /* Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) */
+#define                AT91_MATRIX_RCB1                (1 << 1)        /* Remap Command for AHB Master 1 (ARM926EJ-S Data Master) */
+
+#define AT91_MATRIX_SFR0       (AT91_MATRIX + 0x110)   /* Special Function Register 0 */
+#define AT91_MATRIX_SFR1       (AT91_MATRIX + 0x114)   /* Special Function Register 1 */
+#define AT91_MATRIX_SFR2       (AT91_MATRIX + 0x118)   /* Special Function Register 2 */
+#define AT91_MATRIX_SFR3       (AT91_MATRIX + 0x11C)   /* Special Function Register 3 */
+#define AT91_MATRIX_SFR4       (AT91_MATRIX + 0x120)   /* Special Function Register 4 */
+#define AT91_MATRIX_SFR5       (AT91_MATRIX + 0x124)   /* Special Function Register 5 */
+#define AT91_MATRIX_SFR6       (AT91_MATRIX + 0x128)   /* Special Function Register 6 */
+#define AT91_MATRIX_SFR7       (AT91_MATRIX + 0x12C)   /* Special Function Register 7 */
+#define AT91_MATRIX_SFR8       (AT91_MATRIX + 0x130)   /* Special Function Register 8 */
+#define AT91_MATRIX_SFR9       (AT91_MATRIX + 0x134)   /* Special Function Register 9 */
+#define AT91_MATRIX_SFR10      (AT91_MATRIX + 0x138)   /* Special Function Register 10 */
+#define AT91_MATRIX_SFR11      (AT91_MATRIX + 0x13C)   /* Special Function Register 11 */
+#define AT91_MATRIX_SFR12      (AT91_MATRIX + 0x140)   /* Special Function Register 12 */
+#define AT91_MATRIX_SFR13      (AT91_MATRIX + 0x144)   /* Special Function Register 13 */
+#define AT91_MATRIX_SFR14      (AT91_MATRIX + 0x148)   /* Special Function Register 14 */
+#define AT91_MATRIX_SFR15      (AT91_MATRIX + 0x14C)   /* Special Function Register 15 */
+
+
+/*
+ * The following registers / bits are not defined in the Datasheet (Revision A)
+ */
+
+#define AT91_MATRIX_TCR                (AT91_MATRIX + 0x100)   /* TCM Configuration Register */
+#define                AT91_MATRIX_ITCM_SIZE           (0xf << 0)      /* Size of ITCM enabled memory block */
+#define                        AT91_MATRIX_ITCM_0              (0 << 0)
+#define                        AT91_MATRIX_ITCM_16             (5 << 0)
+#define                        AT91_MATRIX_ITCM_32             (6 << 0)
+#define                        AT91_MATRIX_ITCM_64             (7 << 0)
+#define                AT91_MATRIX_DTCM_SIZE           (0xf << 4)      /* Size of DTCM enabled memory block */
+#define                        AT91_MATRIX_DTCM_0              (0 << 4)
+#define                        AT91_MATRIX_DTCM_16             (5 << 4)
+#define                        AT91_MATRIX_DTCM_32             (6 << 4)
+#define                        AT91_MATRIX_DTCM_64             (7 << 4)
+
+#define AT91_MATRIX_EBICSA     (AT91_MATRIX + 0x11C)   /* EBI Chip Select Assignment Register */
+#define                AT91_MATRIX_CS1A                (1 << 1)        /* Chip Select 1 Assignment */
+#define                        AT91_MATRIX_CS1A_SMC            (0 << 1)
+#define                        AT91_MATRIX_CS1A_SDRAMC         (1 << 1)
+#define                AT91_MATRIX_CS3A                (1 << 3)        /* Chip Select 3 Assignment */
+#define                        AT91_MATRIX_CS3A_SMC            (0 << 3)
+#define                        AT91_MATRIX_CS3A_SMC_SMARTMEDIA (1 << 3)
+#define                AT91_MATRIX_CS4A                (1 << 4)        /* Chip Select 4 Assignment */
+#define                        AT91_MATRIX_CS4A_SMC            (0 << 4)
+#define                        AT91_MATRIX_CS4A_SMC_CF1        (1 << 4)
+#define                AT91_MATRIX_CS5A                (1 << 5)        /* Chip Select 5 Assignment */
+#define                        AT91_MATRIX_CS5A_SMC            (0 << 5)
+#define                        AT91_MATRIX_CS5A_SMC_CF2        (1 << 5)
+#define                AT91_MATRIX_DBPUC               (1 << 8)        /* Data Bus Pull-up Configuration */
+
+#endif
index 64589eaaaee8f8d57ae9044ed587eaa2bd329f66..e46f93e34aab4666b14932a9c6c451847b2c8b54 100644 (file)
@@ -32,6 +32,7 @@
 #define                AT91_PMC_PCK1           (1 <<  9)               /* Programmable Clock 1 */
 #define                AT91_PMC_PCK2           (1 << 10)               /* Programmable Clock 2 */
 #define                AT91_PMC_PCK3           (1 << 11)               /* Programmable Clock 3 */
+#define                AT91_PMC_PCK4           (1 << 12)               /* Programmable Clock 4 [AT572D940HF only] */
 #define                AT91_PMC_HCK0           (1 << 16)               /* AHB Clock (USB host) [AT91SAM9261 only] */
 #define                AT91_PMC_HCK1           (1 << 17)               /* AHB Clock (LCD) [AT91SAM9261 only] */
 
index bb6f6a7ba5e0bf387ed00985caa03e65f2e988a2..ceaec6c16eb2d801e68f50f8ea6975293027af42 100644 (file)
@@ -87,7 +87,7 @@ struct at91_eth_data {
 extern void __init at91_add_device_eth(struct at91_eth_data *data);
 
 #if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9263) || defined(CONFIG_ARCH_AT91SAM9G20) || defined(CONFIG_ARCH_AT91CAP9) \
-       || defined(CONFIG_ARCH_AT91SAM9G45)
+       || defined(CONFIG_ARCH_AT91SAM9G45) || defined(CONFIG_ARCH_AT572D940HF)
 #define eth_platform_data      at91_eth_data
 #endif
 
@@ -205,6 +205,9 @@ extern void __init at91_init_leds(u8 cpu_led, u8 timer_led);
 extern void __init at91_gpio_leds(struct gpio_led *leds, int nr);
 extern void __init at91_pwm_leds(struct gpio_led *leds, int nr);
 
+ /* AT572D940HF DSP */
+extern void __init at91_add_device_mAgic(void);
+
 /* FIXME: this needs a better location, but gets stuff building again */
 extern int at91_suspend_entering_slow_clock(void);
 
index c22df30ed5e5d5784a6d7f09350ea17cd6b53706..5a0650101d45f20112b46cb31bddb1b32000a430 100644 (file)
@@ -33,6 +33,8 @@
 #define ARCH_ID_AT91SAM9XE256  0x329a93a0
 #define ARCH_ID_AT91SAM9XE512  0x329aa3a0
 
+#define ARCH_ID_AT572D940HF    0x0e0303e0
+
 #define ARCH_ID_AT91M40800     0x14080044
 #define ARCH_ID_AT91R40807     0x44080746
 #define ARCH_ID_AT91M40807     0x14080745
@@ -141,6 +143,12 @@ static inline unsigned long at91cap9_rev_identify(void)
 #define cpu_is_at91cap9_revC() (0)
 #endif
 
+#ifdef CONFIG_ARCH_AT572D940HF
+#define cpu_is_at572d940hf() (at91_cpu_identify() == ARCH_ID_AT572D940HF)
+#else
+#define cpu_is_at572d940hf() (0)
+#endif
+
 /*
  * Since this is ARM, we will never run on any AVR32 CPU. But these
  * definitions may reduce clutter in common drivers.
index 29052ba66adac42eb0ee585ecd8bc64e09d9da59..9e750a1c1b5a80fbab076f70314f8ffd7f5a1bd2 100644 (file)
@@ -14,7 +14,7 @@
 #include <mach/hardware.h>
 #include <mach/at91_dbgu.h>
 
-       .macro  addruart,rx
+       .macro  addruart, rx, tmp
        mrc     p15, 0, \rx, c1, c0
        tst     \rx, #1                                         @ MMU enabled?
        ldreq   \rx, =(AT91_BASE_SYS + AT91_DBGU)               @ System peripherals (phys address)
index a0df8b022df27bd3ede5e22aa2d3dff3f9c98fd3..3d64a75e3ed5be8a0566b343653b3af965a47c6f 100644 (file)
@@ -32,6 +32,8 @@
 #include <mach/at91cap9.h>
 #elif defined(CONFIG_ARCH_AT91X40)
 #include <mach/at91x40.h>
+#elif defined(CONFIG_ARCH_AT572D940HF)
+#include <mach/at572d940hf.h>
 #else
 #error "Unsupported AT91 processor"
 #endif
index 31ac2d97f14cb24b85371b259a2c70b27fc6a461..05a6e8af80c4e1f3c4b4983c88821c1e1bd0ad26 100644 (file)
 #define AT91X40_MASTER_CLOCK   40000000
 #define CLOCK_TICK_RATE                (AT91X40_MASTER_CLOCK)
 
+#elif defined(CONFIG_ARCH_AT572D940HF)
+
+#define AT572D940HF_MASTER_CLOCK       80000000
+#define CLOCK_TICK_RATE                (AT572D940HF_MASTER_CLOCK/16)
+
 #endif
 
 #endif
index e590bbe0a7b46acb51e42baba1c5344239a29753..72e405df0fb07dd4b363153f149742875725f7ad 100644 (file)
@@ -142,8 +142,7 @@ void __init bcmring_amba_init(void)
 
        chipcHw_busInterfaceClockEnable(bus_clock);
 
-       for (i = 0; i < ARRAY_SIZE(lookups); i++)
-               clkdev_add(&lookups[i]);
+       clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
        for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
                struct amba_device *d = amba_devs[i];
index 64baf9f874087c8df7f7fc47e83c4c189f592978..fedd8076a689a3555a986b5e96bc9348cf4ae77f 100644 (file)
@@ -13,7 +13,7 @@
 
 #include <asm/hardware/clps7111.h>
 
-               .macro  addruart,rx
+               .macro  addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                 @ MMU enabled?
                moveq   \rx, #CLPS7111_PHYS_BASE
index 033bfede6b67d5dcaa26aa22b6641f8bfbe0efc4..0ebe185610bf80810f6cbfa5e0bf43466186a484 100644 (file)
@@ -91,10 +91,14 @@ config MACH_DAVINCI_DM6467_EVM
        bool "TI DM6467 EVM"
        default ARCH_DAVINCI_DM646x
        depends on ARCH_DAVINCI_DM646x
+       select MACH_DAVINCI_DM6467TEVM
        help
          Configure this option to specify the whether the board used
          for development is a DM6467 EVM
 
+config MACH_DAVINCI_DM6467TEVM
+       bool
+
 config MACH_DAVINCI_DM365_EVM
        bool "TI DM365 EVM"
        default ARCH_DAVINCI_DM365
index eeb9230d8844d3f9c2e6fe5a451d8ac6e3c63657..6aac880eb79422dc13c5cee16b47f91fd7902bb1 100644 (file)
@@ -26,7 +26,7 @@ obj-$(CONFIG_MACH_SFFSDR)             += board-sffsdr.o
 obj-$(CONFIG_MACH_NEUROS_OSD2)         += board-neuros-osd2.o
 obj-$(CONFIG_MACH_DAVINCI_DM355_EVM)   += board-dm355-evm.o
 obj-$(CONFIG_MACH_DM355_LEOPARD)       += board-dm355-leopard.o
-obj-$(CONFIG_MACH_DAVINCI_DM6467_EVM)  += board-dm646x-evm.o
+obj-$(CONFIG_MACH_DAVINCI_DM6467_EVM)  += board-dm646x-evm.o cdce949.o
 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
@@ -34,3 +34,4 @@ obj-$(CONFIG_MACH_DAVINCI_DA850_EVM)  += board-da850-evm.o
 # Power Management
 obj-$(CONFIG_CPU_FREQ)                 += cpufreq.o
 obj-$(CONFIG_CPU_IDLE)                 += cpuidle.o
+obj-$(CONFIG_SUSPEND)                  += pm.o sleep.o
index 31dc9901e5569e6ea16220c22d919079965ff274..dc19870b23cd326dcc99795266d00f85df08da7f 100644 (file)
@@ -112,7 +112,7 @@ static __init void da830_evm_usb_init(void)
         * Set up USB clock/mode in the CFGCHIP2 register.
         * FYI:  CFGCHIP2 is 0x0000ef00 initially.
         */
-       cfgchip2 = __raw_readl(DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP2_REG));
+       cfgchip2 = __raw_readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
 
        /* USB2.0 PHY reference clock is 24 MHz */
        cfgchip2 &= ~CFGCHIP2_REFFREQ;
@@ -139,7 +139,7 @@ static __init void da830_evm_usb_init(void)
        cfgchip2 |=  CFGCHIP2_SESENDEN | CFGCHIP2_VBDTCTEN;
 #endif
 
-       __raw_writel(cfgchip2, DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP2_REG));
+       __raw_writel(cfgchip2, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
 
        /* USB_REFCLKIN is not used. */
        ret = davinci_cfg_reg(DA830_USB0_DRVVBUS);
index 07de8db145812c68a6cf386ef68ff10c2251f9b7..411284d0b0faab646d6c39d1d0fe8c5259ca70fd 100644 (file)
 
 static struct mtd_partition da850_evm_norflash_partition[] = {
        {
-               .name           = "NOR filesystem",
+               .name           = "bootloaders + env",
                .offset         = 0,
+               .size           = SZ_512K,
+               .mask_flags     = MTD_WRITEABLE,
+       },
+       {
+               .name           = "kernel",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = SZ_2M,
+               .mask_flags     = 0,
+       },
+       {
+               .name           = "filesystem",
+               .offset         = MTDPART_OFS_APPEND,
                .size           = MTDPART_SIZ_FULL,
                .mask_flags     = 0,
        },
@@ -77,6 +89,18 @@ static struct platform_device da850_evm_norflash_device = {
        .resource       = da850_evm_norflash_resource,
 };
 
+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,
+};
+
 /* DA850/OMAP-L138 EVM includes a 512 MByte large-page NAND flash
  * (128K blocks). It may be used instead of the (default) SPI flash
  * to boot, using TI's tools to install the secondary boot loader
@@ -119,6 +143,7 @@ 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,
 };
 
@@ -537,7 +562,7 @@ static int __init da850_evm_config_emac(void)
        if (!machine_is_davinci_da850_evm())
                return 0;
 
-       cfg_chip3_base = DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP3_REG);
+       cfg_chip3_base = DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP3_REG);
 
        val = __raw_readl(cfg_chip3_base);
 
@@ -696,6 +721,11 @@ static __init void da850_evm_init(void)
        if (ret)
                pr_warning("da850_evm_init: 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
index 077ecf4fecda9fb21dc98e002f4f236a8488fed9..aa48e3f69715b2163f6d4175e8264cf022dca4ac 100644 (file)
@@ -111,6 +111,8 @@ static struct platform_device davinci_nand_device = {
 static struct davinci_i2c_platform_data i2c_pdata = {
        .bus_freq       = 400   /* kHz */,
        .bus_delay      = 0     /* usec */,
+       .sda_pin        = 15,
+       .scl_pin        = 14,
 };
 
 static struct snd_platform_data dm355_evm_snd_data;
index 38e9033d2e86dfe0e70b09e91edf58a907034f44..d15beceb632e9bcd784996dbd908ee1261d84994 100644 (file)
@@ -24,6 +24,8 @@
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/nand.h>
 #include <linux/input.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/eeprom.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -571,6 +573,24 @@ static void __init dm365_evm_map_io(void)
        dm365_init();
 }
 
+static struct spi_eeprom at25640 = {
+       .byte_len       = SZ_64K / 8,
+       .name           = "at25640",
+       .page_size      = 32,
+       .flags          = EE_ADDR2,
+};
+
+static struct spi_board_info dm365_evm_spi_info[] __initconst = {
+       {
+               .modalias       = "at25",
+               .platform_data  = &at25640,
+               .max_speed_hz   = 10 * 1000 * 1000,
+               .bus_num        = 0,
+               .chip_select    = 0,
+               .mode           = SPI_MODE_0,
+       },
+};
+
 static __init void dm365_evm_init(void)
 {
        evm_init_i2c();
@@ -587,6 +607,9 @@ static __init void dm365_evm_init(void)
        dm365_init_asp(&dm365_evm_snd_data);
        dm365_init_rtc();
        dm365_init_ks(&dm365evm_ks_data);
+
+       dm365_init_spi0(BIT(0), dm365_evm_spi_info,
+                       ARRAY_SIZE(dm365_evm_spi_info));
 }
 
 static __init void dm365_evm_irq_init(void)
index e9612cf727b7cc9c6bb19a570ed0bc0b6d92ad52..976e11b7fa4a3655c2bfa012fcc7681f79efbc89 100644 (file)
@@ -629,6 +629,8 @@ static struct i2c_board_info __initdata i2c_info[] =  {
 static struct davinci_i2c_platform_data i2c_pdata = {
        .bus_freq       = 20 /* kHz */,
        .bus_delay      = 100 /* usec */,
+       .sda_pin        = 44,
+       .scl_pin        = 43,
 };
 
 static void __init evm_init_i2c(void)
index 8d0b0e01c59b6deee93e12bb5eb13998873cc2e1..5ba3cb2daaa0d71bc8a57a403ab2272b1e515232 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
+#include <linux/clk.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <mach/serial.h>
 #include <mach/i2c.h>
 #include <mach/nand.h>
+#include <mach/clock.h>
+#include <mach/cdce949.h>
 
-#if defined(CONFIG_BLK_DEV_PALMCHIP_BK3710) || \
-    defined(CONFIG_BLK_DEV_PALMCHIP_BK3710_MODULE)
-#define HAS_ATA 1
-#else
-#define HAS_ATA 0
-#endif
-
-#define DAVINCI_ASYNC_EMIF_CONTROL_BASE                0x20008000
-#define DAVINCI_ASYNC_EMIF_DATA_CE0_BASE       0x42000000
+#include "clock.h"
 
 #define NAND_BLOCK_SIZE                SZ_128K
 
-/* CPLD Register 0 bits to control ATA */
-#define DM646X_EVM_ATA_RST             BIT(0)
-#define DM646X_EVM_ATA_PWD             BIT(1)
-
-#define DM646X_EVM_PHY_MASK            (0x2)
-#define DM646X_EVM_MDIO_FREQUENCY      (2200000) /* PHY bus frequency */
-
-#define VIDCLKCTL_OFFSET       (DAVINCI_SYSTEM_MODULE_BASE + 0x38)
-#define VSCLKDIS_OFFSET                (DAVINCI_SYSTEM_MODULE_BASE + 0x6c)
-#define VCH2CLK_MASK           (BIT_MASK(10) | BIT_MASK(9) | BIT_MASK(8))
-#define VCH2CLK_SYSCLK8                (BIT(9))
-#define VCH2CLK_AUXCLK         (BIT(9) | BIT(8))
-#define VCH3CLK_MASK           (BIT_MASK(14) | BIT_MASK(13) | BIT_MASK(12))
-#define VCH3CLK_SYSCLK8                (BIT(13))
-#define VCH3CLK_AUXCLK         (BIT(14) | BIT(13))
-
-#define VIDCH2CLK              (BIT(10))
-#define VIDCH3CLK              (BIT(11))
-#define VIDCH1CLK              (BIT(4))
-#define TVP7002_INPUT          (BIT(4))
-#define TVP5147_INPUT          (~BIT(4))
-#define VPIF_INPUT_ONE_CHANNEL (BIT(5))
-#define VPIF_INPUT_TWO_CHANNEL (~BIT(5))
-#define TVP5147_CH0            "tvp514x-0"
-#define TVP5147_CH1            "tvp514x-1"
-
-static void __iomem *vpif_vidclkctl_reg;
-static void __iomem *vpif_vsclkdis_reg;
-/* spin lock for updating above registers */
-static spinlock_t vpif_reg_lock;
-
-static struct davinci_uart_config uart_config __initdata = {
-       .enabled_uarts = (1 << 0),
-};
-
 /* Note: We are setting first partition as 'bootloader' constituting UBL, U-Boot
  * and U-Boot environment this avoids dependency on any particular combination
  * of UBL, U-Boot or flashing tools etc.
@@ -120,6 +80,9 @@ static struct davinci_nand_pdata davinci_nand_data = {
        .options                = 0,
 };
 
+#define DAVINCI_ASYNC_EMIF_CONTROL_BASE                0x20008000
+#define DAVINCI_ASYNC_EMIF_DATA_CE0_BASE       0x42000000
+
 static struct resource davinci_nand_resources[] = {
        {
                .start          = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE,
@@ -144,6 +107,17 @@ static struct platform_device davinci_nand_device = {
        },
 };
 
+#if defined(CONFIG_BLK_DEV_PALMCHIP_BK3710) || \
+    defined(CONFIG_BLK_DEV_PALMCHIP_BK3710_MODULE)
+#define HAS_ATA 1
+#else
+#define HAS_ATA 0
+#endif
+
+/* CPLD Register 0 bits to control ATA */
+#define DM646X_EVM_ATA_RST             BIT(0)
+#define DM646X_EVM_ATA_PWD             BIT(1)
+
 /* CPLD Register 0 Client: used for I/O Control */
 static int cpld_reg0_probe(struct i2c_client *client,
                           const struct i2c_device_id *id)
@@ -417,6 +391,9 @@ static struct i2c_board_info __initdata i2c_info[] =  {
        {
                I2C_BOARD_INFO("cpld_video", 0x3b),
        },
+       {
+               I2C_BOARD_INFO("cdce949", 0x6c),
+       },
 };
 
 static struct davinci_i2c_platform_data i2c_pdata = {
@@ -424,6 +401,30 @@ static struct davinci_i2c_platform_data i2c_pdata = {
        .bus_delay      = 0 /* usec */,
 };
 
+#define VIDCLKCTL_OFFSET       (DAVINCI_SYSTEM_MODULE_BASE + 0x38)
+#define VSCLKDIS_OFFSET                (DAVINCI_SYSTEM_MODULE_BASE + 0x6c)
+#define VCH2CLK_MASK           (BIT_MASK(10) | BIT_MASK(9) | BIT_MASK(8))
+#define VCH2CLK_SYSCLK8                (BIT(9))
+#define VCH2CLK_AUXCLK         (BIT(9) | BIT(8))
+#define VCH3CLK_MASK           (BIT_MASK(14) | BIT_MASK(13) | BIT_MASK(12))
+#define VCH3CLK_SYSCLK8                (BIT(13))
+#define VCH3CLK_AUXCLK         (BIT(14) | BIT(13))
+
+#define VIDCH2CLK              (BIT(10))
+#define VIDCH3CLK              (BIT(11))
+#define VIDCH1CLK              (BIT(4))
+#define TVP7002_INPUT          (BIT(4))
+#define TVP5147_INPUT          (~BIT(4))
+#define VPIF_INPUT_ONE_CHANNEL (BIT(5))
+#define VPIF_INPUT_TWO_CHANNEL (~BIT(5))
+#define TVP5147_CH0            "tvp514x-0"
+#define TVP5147_CH1            "tvp514x-1"
+
+static void __iomem *vpif_vidclkctl_reg;
+static void __iomem *vpif_vsclkdis_reg;
+/* spin lock for updating above registers */
+static spinlock_t vpif_reg_lock;
+
 static int set_vpif_clock(int mux_mode, int hd)
 {
        unsigned long flags;
@@ -685,11 +686,44 @@ static void __init evm_init_i2c(void)
        evm_init_video();
 }
 
+#define CDCE949_XIN_RATE       27000000
+
+/* CDCE949 support - "lpsc" field is overridden to work as clock number */
+static struct clk cdce_clk_in = {
+       .name   = "cdce_xin",
+       .rate   = CDCE949_XIN_RATE,
+};
+
+static struct clk_lookup cdce_clks[] = {
+       CLK(NULL, "xin", &cdce_clk_in),
+       CLK(NULL, NULL, NULL),
+};
+
+static void __init cdce_clk_init(void)
+{
+       struct clk_lookup *c;
+       struct clk *clk;
+
+       for (c = cdce_clks; c->clk; c++) {
+               clk = c->clk;
+               clkdev_add(c);
+               clk_register(clk);
+       }
+}
+
 static void __init davinci_map_io(void)
 {
        dm646x_init();
+       cdce_clk_init();
 }
 
+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 */
+
 static __init void evm_init(void)
 {
        struct davinci_soc_info *soc_info = &davinci_soc_info;
@@ -713,6 +747,17 @@ static __init void davinci_dm646x_evm_irq_init(void)
        davinci_irq_init();
 }
 
+#define DM646X_EVM_REF_FREQ            27000000
+#define DM6467T_EVM_REF_FREQ           33000000
+
+void __init dm646x_board_setup_refclk(struct clk *clk)
+{
+       if (machine_is_davinci_dm6467tevm())
+               clk->rate = DM6467T_EVM_REF_FREQ;
+       else
+               clk->rate = DM646X_EVM_REF_FREQ;
+}
+
 MACHINE_START(DAVINCI_DM6467_EVM, "DaVinci DM646x EVM")
        .phys_io      = IO_PHYS,
        .io_pg_offst  = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
@@ -723,3 +768,13 @@ MACHINE_START(DAVINCI_DM6467_EVM, "DaVinci DM646x EVM")
        .init_machine = evm_init,
 MACHINE_END
 
+MACHINE_START(DAVINCI_DM6467TEVM, "DaVinci DM6467T EVM")
+       .phys_io      = IO_PHYS,
+       .io_pg_offst  = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
+       .boot_params  = (0x80000100),
+       .map_io       = davinci_map_io,
+       .init_irq     = davinci_dm646x_evm_irq_init,
+       .timer        = &davinci_timer,
+       .init_machine = evm_init,
+MACHINE_END
+
diff --git a/arch/arm/mach-davinci/cdce949.c b/arch/arm/mach-davinci/cdce949.c
new file mode 100644 (file)
index 0000000..aec3756
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ * TI CDCE949 clock synthesizer driver
+ *
+ * Note: This implementation assumes an input of 27MHz to the CDCE.
+ * This is by no means constrained by CDCE hardware although the datasheet
+ * does use this as an example for all illustrations and more importantly:
+ * that is the crystal input on boards it is currently used on.
+ *
+ * Copyright (C) 2009 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/clk.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+
+#include <mach/clock.h>
+
+#include "clock.h"
+
+static struct i2c_client *cdce_i2c_client;
+static DEFINE_MUTEX(cdce_mutex);
+
+/* CDCE register descriptor */
+struct cdce_reg {
+       u8      addr;
+       u8      val;
+};
+
+/* Per-Output (Y1, Y2 etc.) frequency descriptor */
+struct cdce_freq {
+       /* Frequency in KHz */
+       unsigned long frequency;
+       /*
+        * List of registers to program to obtain a particular frequency.
+        * 0x0 in register address and value is the end of list marker.
+        */
+       struct cdce_reg *reglist;
+};
+
+#define CDCE_FREQ_TABLE_ENTRY(line, out)               \
+{                                                      \
+       .reglist        = cdce_y ##line## _ ##out,              \
+       .frequency      = out,                          \
+}
+
+/* List of CDCE outputs  */
+struct cdce_output {
+       /* List of frequencies on this output */
+       struct cdce_freq *freq_table;
+       /* Number of possible frequencies */
+       int size;
+};
+
+/*
+ * Finding out the values to program into CDCE949 registers for a particular
+ * frequency output is not a simple calculation. Have a look at the datasheet
+ * for the details. There is desktop software available to help users with
+ * the calculations. Here, we just depend on the output of that software
+ * (or hand calculations) instead trying to runtime calculate the register
+ * values and inflicting misery on ourselves.
+ */
+static struct cdce_reg cdce_y1_148500[] = {
+       { 0x13, 0x00 },
+       /* program PLL1_0 multiplier */
+       { 0x18, 0xaf },
+       { 0x19, 0x50 },
+       { 0x1a, 0x02 },
+       { 0x1b, 0xc9 },
+       /* program PLL1_11 multiplier */
+       { 0x1c, 0x00 },
+       { 0x1d, 0x40 },
+       { 0x1e, 0x02 },
+       { 0x1f, 0xc9 },
+       /* output state selection */
+       { 0x15, 0x00 },
+       { 0x14, 0xef },
+       /* switch MUX to PLL1 output */
+       { 0x14, 0x6f },
+       { 0x16, 0x06 },
+       /* set P2DIV divider, P3DIV and input crystal */
+       { 0x17, 0x06 },
+       { 0x01, 0x00 },
+       { 0x05, 0x48 },
+       { 0x02, 0x80 },
+       /* enable and disable PLL */
+       { 0x02, 0xbc },
+       { 0x03, 0x01 },
+       { },
+};
+
+static struct cdce_reg cdce_y1_74250[] = {
+       { 0x13, 0x00 },
+       { 0x18, 0xaf },
+       { 0x19, 0x50 },
+       { 0x1a, 0x02 },
+       { 0x1b, 0xc9 },
+       { 0x1c, 0x00 },
+       { 0x1d, 0x40 },
+       { 0x1e, 0x02 },
+       { 0x1f, 0xc9 },
+       /* output state selection */
+       { 0x15, 0x00 },
+       { 0x14, 0xef },
+       /* switch MUX to PLL1 output */
+       { 0x14, 0x6f },
+       { 0x16, 0x06 },
+       /* set P2DIV divider, P3DIV and input crystal */
+       { 0x17, 0x06 },
+       { 0x01, 0x00 },
+       { 0x05, 0x48 },
+       { 0x02, 0x80 },
+       /* enable and disable PLL */
+       { 0x02, 0xbc },
+       { 0x03, 0x02 },
+       { },
+};
+
+static struct cdce_reg cdce_y1_27000[] = {
+       { 0x13, 0x00 },
+       { 0x18, 0x00 },
+       { 0x19, 0x40 },
+       { 0x1a, 0x02 },
+       { 0x1b, 0x08 },
+       { 0x1c, 0x00 },
+       { 0x1d, 0x40 },
+       { 0x1e, 0x02 },
+       { 0x1f, 0x08 },
+       { 0x15, 0x02 },
+       { 0x14, 0xed },
+       { 0x16, 0x01 },
+       { 0x17, 0x01 },
+       { 0x01, 0x00 },
+       { 0x05, 0x50 },
+       { 0x02, 0xb4 },
+       { 0x03, 0x01 },
+       { },
+};
+
+static struct cdce_freq cdce_y1_freqs[] = {
+       CDCE_FREQ_TABLE_ENTRY(1, 148500),
+       CDCE_FREQ_TABLE_ENTRY(1, 74250),
+       CDCE_FREQ_TABLE_ENTRY(1, 27000),
+};
+
+static struct cdce_reg cdce_y5_13500[] = {
+       { 0x27, 0x08 },
+       { 0x28, 0x00 },
+       { 0x29, 0x40 },
+       { 0x2a, 0x02 },
+       { 0x2b, 0x08 },
+       { 0x24, 0x6f },
+       { },
+};
+
+static struct cdce_reg cdce_y5_16875[] = {
+       { 0x27, 0x08 },
+       { 0x28, 0x9f },
+       { 0x29, 0xb0 },
+       { 0x2a, 0x02 },
+       { 0x2b, 0x89 },
+       { 0x24, 0x6f },
+       { },
+};
+
+static struct cdce_reg cdce_y5_27000[] = {
+       { 0x27, 0x04 },
+       { 0x28, 0x00 },
+       { 0x29, 0x40 },
+       { 0x2a, 0x02 },
+       { 0x2b, 0x08 },
+       { 0x24, 0x6f },
+       { },
+};
+static struct cdce_reg cdce_y5_54000[] = {
+       { 0x27, 0x04 },
+       { 0x28, 0xff },
+       { 0x29, 0x80 },
+       { 0x2a, 0x02 },
+       { 0x2b, 0x07 },
+       { 0x24, 0x6f },
+       { },
+};
+
+static struct cdce_reg cdce_y5_81000[] = {
+       { 0x27, 0x02 },
+       { 0x28, 0xbf },
+       { 0x29, 0xa0 },
+       { 0x2a, 0x03 },
+       { 0x2b, 0x0a },
+       { 0x24, 0x6f },
+       { },
+};
+
+static struct cdce_freq cdce_y5_freqs[] = {
+       CDCE_FREQ_TABLE_ENTRY(5, 13500),
+       CDCE_FREQ_TABLE_ENTRY(5, 16875),
+       CDCE_FREQ_TABLE_ENTRY(5, 27000),
+       CDCE_FREQ_TABLE_ENTRY(5, 54000),
+       CDCE_FREQ_TABLE_ENTRY(5, 81000),
+};
+
+
+static struct cdce_output output_list[] = {
+       [1]     = { cdce_y1_freqs, ARRAY_SIZE(cdce_y1_freqs) },
+       [5]     = { cdce_y5_freqs, ARRAY_SIZE(cdce_y5_freqs) },
+};
+
+int cdce_set_rate(struct clk *clk, unsigned long rate)
+{
+       int i, ret = 0;
+       struct cdce_freq *freq_table = output_list[clk->lpsc].freq_table;
+       struct cdce_reg  *regs = NULL;
+
+       if (!cdce_i2c_client)
+               return -ENODEV;
+
+       if (!freq_table)
+               return -EINVAL;
+
+       for (i = 0; i < output_list[clk->lpsc].size; i++) {
+               if (freq_table[i].frequency == rate / 1000) {
+                       regs = freq_table[i].reglist;
+                       break;
+               }
+       }
+
+       if (!regs)
+               return -EINVAL;
+
+       mutex_lock(&cdce_mutex);
+       for (i = 0; regs[i].addr; i++) {
+               ret = i2c_smbus_write_byte_data(cdce_i2c_client,
+                                       regs[i].addr | 0x80, regs[i].val);
+               if (ret)
+                       break;
+       }
+       mutex_unlock(&cdce_mutex);
+
+       if (!ret)
+               clk->rate = rate;
+
+       return ret;
+}
+
+static int cdce_probe(struct i2c_client *client,
+                                       const struct i2c_device_id *id)
+{
+       cdce_i2c_client = client;
+       return 0;
+}
+
+static int __devexit cdce_remove(struct i2c_client *client)
+{
+       cdce_i2c_client = NULL;
+       return 0;
+}
+
+static const struct i2c_device_id cdce_id[] = {
+       {"cdce949", 0},
+       {},
+};
+MODULE_DEVICE_TABLE(i2c, cdce_id);
+
+static struct i2c_driver cdce_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "cdce949",
+       },
+       .probe          = cdce_probe,
+       .remove         = __devexit_p(cdce_remove),
+       .id_table       = cdce_id,
+};
+
+static int __init cdce_init(void)
+{
+       return i2c_add_driver(&cdce_driver);
+}
+subsys_initcall(cdce_init);
+
+static void __exit cdce_exit(void)
+{
+       i2c_del_driver(&cdce_driver);
+}
+module_exit(cdce_exit);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("CDCE949 clock synthesizer driver");
+MODULE_LICENSE("GPL v2");
index baece65cb9c0829ed04bfc210e8894f075512bbe..bf6218ee94e193a69b9de7ef1da240f2d320e16b 100644 (file)
@@ -49,7 +49,8 @@ static void __clk_disable(struct clk *clk)
 {
        if (WARN_ON(clk->usecount == 0))
                return;
-       if (--clk->usecount == 0 && !(clk->flags & CLK_PLL))
+       if (--clk->usecount == 0 && !(clk->flags & CLK_PLL) &&
+           (clk->flags & CLK_PSC))
                davinci_psc_config(psc_domain(clk), clk->gpsc, clk->lpsc, 0);
        if (clk->parent)
                __clk_disable(clk->parent);
@@ -124,9 +125,10 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
        if (clk == NULL || IS_ERR(clk))
                return ret;
 
-       spin_lock_irqsave(&clockfw_lock, flags);
        if (clk->set_rate)
                ret = clk->set_rate(clk, rate);
+
+       spin_lock_irqsave(&clockfw_lock, flags);
        if (ret == 0) {
                if (clk->recalc)
                        clk->rate = clk->recalc(clk);
@@ -363,6 +365,7 @@ int davinci_set_pllrate(struct pll_data *pll, unsigned int prediv,
 {
        u32 ctrl;
        unsigned int locktime;
+       unsigned long flags;
 
        if (pll->base == NULL)
                return -EINVAL;
@@ -376,25 +379,23 @@ int davinci_set_pllrate(struct pll_data *pll, unsigned int prediv,
                locktime = ((2000 * prediv) / 100);
                prediv = (prediv - 1) | PLLDIV_EN;
        } else {
-               locktime = 20;
+               locktime = PLL_LOCK_TIME;
        }
        if (postdiv)
                postdiv = (postdiv - 1) | PLLDIV_EN;
        if (mult)
                mult = mult - 1;
 
+       /* Protect against simultaneous calls to PLL setting seqeunce */
+       spin_lock_irqsave(&clockfw_lock, flags);
+
        ctrl = __raw_readl(pll->base + PLLCTL);
 
        /* Switch the PLL to bypass mode */
        ctrl &= ~(PLLCTL_PLLENSRC | PLLCTL_PLLEN);
        __raw_writel(ctrl, pll->base + PLLCTL);
 
-       /*
-        * Wait for 4 OSCIN/CLKIN cycles to ensure that the PLLC has switched
-        * to bypass mode. Delay of 1us ensures we are good for all > 4MHz
-        * OSCIN/CLKIN inputs. Typically the input is ~25MHz.
-        */
-       udelay(1);
+       udelay(PLL_BYPASS_TIME);
 
        /* Reset and enable PLL */
        ctrl &= ~(PLLCTL_PLLRST | PLLCTL_PLLDIS);
@@ -408,11 +409,7 @@ int davinci_set_pllrate(struct pll_data *pll, unsigned int prediv,
        if (pll->flags & PLL_HAS_POSTDIV)
                __raw_writel(postdiv, pll->base + POSTDIV);
 
-       /*
-        * Wait for PLL to reset properly, OMAP-L138 datasheet says
-        * 'min' time = 125ns
-        */
-       udelay(1);
+       udelay(PLL_RESET_TIME);
 
        /* Bring PLL out of reset */
        ctrl |= PLLCTL_PLLRST;
@@ -424,17 +421,20 @@ int davinci_set_pllrate(struct pll_data *pll, unsigned int prediv,
        ctrl |= PLLCTL_PLLEN;
        __raw_writel(ctrl, pll->base + PLLCTL);
 
+       spin_unlock_irqrestore(&clockfw_lock, flags);
+
        return 0;
 }
 EXPORT_SYMBOL(davinci_set_pllrate);
 
-int __init davinci_clk_init(struct davinci_clk *clocks)
+int __init davinci_clk_init(struct clk_lookup *clocks)
   {
-       struct davinci_clk *c;
+       struct clk_lookup *c;
        struct clk *clk;
+       size_t num_clocks = 0;
 
-       for (c = clocks; c->lk.clk; c++) {
-               clk = c->lk.clk;
+       for (c = clocks; c->clk; c++) {
+               clk = c->clk;
 
                if (!clk->recalc) {
 
@@ -457,35 +457,23 @@ int __init davinci_clk_init(struct davinci_clk *clocks)
                if (clk->lpsc)
                        clk->flags |= CLK_PSC;
 
-               clkdev_add(&c->lk);
                clk_register(clk);
+               num_clocks++;
 
                /* Turn on clocks that Linux doesn't otherwise manage */
                if (clk->flags & ALWAYS_ENABLED)
                        clk_enable(clk);
        }
 
-       return 0;
-}
-
-#ifdef CONFIG_PROC_FS
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
+       clkdev_add_table(clocks, num_clocks);
 
-static void *davinci_ck_start(struct seq_file *m, loff_t *pos)
-{
-       return *pos < 1 ? (void *)1 : NULL;
+       return 0;
 }
 
-static void *davinci_ck_next(struct seq_file *m, void *v, loff_t *pos)
-{
-       ++*pos;
-       return NULL;
-}
+#ifdef CONFIG_DEBUG_FS
 
-static void davinci_ck_stop(struct seq_file *m, void *v)
-{
-}
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
 
 #define CLKNAME_MAX    10              /* longest clock name */
 #define NEST_DELTA     2
@@ -525,41 +513,38 @@ dump_clock(struct seq_file *s, unsigned nest, struct clk *parent)
 
 static int davinci_ck_show(struct seq_file *m, void *v)
 {
-       /* Show clock tree; we know the main oscillator is first.
-        * We trust nonzero usecounts equate to PSC enables...
+       struct clk *clk;
+
+       /*
+        * Show clock tree; We trust nonzero usecounts equate to PSC enables...
         */
        mutex_lock(&clocks_mutex);
-       if (!list_empty(&clocks))
-               dump_clock(m, 0, list_first_entry(&clocks, struct clk, node));
+       list_for_each_entry(clk, &clocks, node)
+               if (!clk->parent)
+                       dump_clock(m, 0, clk);
        mutex_unlock(&clocks_mutex);
 
        return 0;
 }
 
-static const struct seq_operations davinci_ck_op = {
-       .start  = davinci_ck_start,
-       .next   = davinci_ck_next,
-       .stop   = davinci_ck_stop,
-       .show   = davinci_ck_show
-};
-
 static int davinci_ck_open(struct inode *inode, struct file *file)
 {
-       return seq_open(file, &davinci_ck_op);
+       return single_open(file, davinci_ck_show, NULL);
 }
 
-static const struct file_operations proc_davinci_ck_operations = {
+static const struct file_operations davinci_ck_operations = {
        .open           = davinci_ck_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
-       .release        = seq_release,
+       .release        = single_release,
 };
 
-static int __init davinci_ck_proc_init(void)
+static int __init davinci_clk_debugfs_init(void)
 {
-       proc_create("davinci_clocks", 0, NULL, &proc_davinci_ck_operations);
+       debugfs_create_file("davinci_clocks", S_IFREG | S_IRUGO, NULL, NULL,
+                                               &davinci_ck_operations);
        return 0;
 
 }
-__initcall(davinci_ck_proc_init);
-#endif /* CONFIG_DEBUG_PROC_FS */
+device_initcall(davinci_clk_debugfs_init);
+#endif /* CONFIG_DEBUG_FS */
index c92d77a3008d8086cb5bfc0016a4f9379aef9753..aa0a611503255a7a7a2d350ada2fab676354f373 100644 (file)
@@ -12,9 +12,6 @@
 #ifndef __ARCH_ARM_DAVINCI_CLOCK_H
 #define __ARCH_ARM_DAVINCI_CLOCK_H
 
-#include <linux/list.h>
-#include <asm/clkdev.h>
-
 #define DAVINCI_PLL1_BASE 0x01c40800
 #define DAVINCI_PLL2_BASE 0x01c40c00
 #define MAX_PLL 2
 #define PLLDIV_EN       BIT(15)
 #define PLLDIV_RATIO_MASK 0x1f
 
+/*
+ * OMAP-L138 system reference guide recommends a wait for 4 OSCIN/CLKIN
+ * cycles to ensure that the PLLC has switched to bypass mode. Delay of 1us
+ * ensures we are good for all > 4MHz OSCIN/CLKIN inputs. Typically the input
+ * is ~25MHz. Units are micro seconds.
+ */
+#define PLL_BYPASS_TIME                1
+/* From OMAP-L138 datasheet table 6-4. Units are micro seconds */
+#define PLL_RESET_TIME         1
+/*
+ * From OMAP-L138 datasheet table 6-4; assuming prediv = 1, sqrt(pllm) = 4
+ * Units are micro seconds.
+ */
+#define PLL_LOCK_TIME          20
+
+#ifndef __ASSEMBLER__
+
+#include <linux/list.h>
+#include <asm/clkdev.h>
+
 struct pll_data {
        u32 phys_base;
        void __iomem *base;
@@ -89,23 +106,19 @@ struct clk {
 #define CLK_PLL                        BIT(4) /* PLL-derived clock */
 #define PRE_PLL                 BIT(5) /* source is before PLL mult/div */
 
-struct davinci_clk {
-       struct clk_lookup lk;
-};
-
-#define CLK(dev, con, ck)              \
-       {                               \
-               .lk = {                 \
-                       .dev_id = dev,  \
-                       .con_id = con,  \
-                       .clk = ck,      \
-               },                      \
-       }
+#define CLK(dev, con, ck)      \
+       {                       \
+               .dev_id = dev,  \
+               .con_id = con,  \
+               .clk = ck,      \
+       }                       \
 
-int davinci_clk_init(struct davinci_clk *clocks);
+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);
 
 extern struct platform_device davinci_wdt_device;
 
 #endif
+
+#endif
index c2de94cde56a85bba11ddc02031ced7876fdc3f4..94f27cbcd55af69aeb6580023676c5543892a1cd 100644 (file)
 #include <linux/module.h>
 #include <linux/io.h>
 #include <linux/etherdevice.h>
+#include <linux/davinci_emac.h>
 
 #include <asm/tlb.h>
 #include <asm/mach/map.h>
 
 #include <mach/common.h>
 #include <mach/cputype.h>
-#include <mach/emac.h>
 
 #include "clock.h"
 
index 97a90f36fc92cd3761c1054f0b2dab5120bd965f..bd59f31b8a95b2a04e0f0d8de50c9122d1831e38 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/proc-fns.h>
 
 #include <mach/cpuidle.h>
+#include <mach/memory.h>
 
 #define DAVINCI_CPUIDLE_MAX_STATES     2
 
@@ -39,10 +40,6 @@ static struct cpuidle_driver davinci_idle_driver = {
 static DEFINE_PER_CPU(struct cpuidle_device, davinci_cpuidle_device);
 static void __iomem *ddr2_reg_base;
 
-#define DDR2_SDRCR_OFFSET      0xc
-#define DDR2_SRPD_BIT          BIT(23)
-#define DDR2_LPMODEN_BIT       BIT(31)
-
 static void davinci_save_ddr_power(int enter, bool pdown)
 {
        u32 val;
@@ -109,8 +106,6 @@ static int __init davinci_cpuidle_probe(struct platform_device *pdev)
        int ret;
        struct cpuidle_device *device;
        struct davinci_cpuidle_config *pdata = pdev->dev.platform_data;
-       struct resource *ddr2_regs;
-       resource_size_t len;
 
        device = &per_cpu(davinci_cpuidle_device, smp_processor_id());
 
@@ -119,28 +114,12 @@ static int __init davinci_cpuidle_probe(struct platform_device *pdev)
                return -ENOENT;
        }
 
-       ddr2_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!ddr2_regs) {
-               dev_err(&pdev->dev, "cannot get DDR2 controller register base");
-               return -ENODEV;
-       }
-
-       len = resource_size(ddr2_regs);
-
-       ddr2_regs = request_mem_region(ddr2_regs->start, len, ddr2_regs->name);
-       if (!ddr2_regs)
-               return -EBUSY;
-
-       ddr2_reg_base = ioremap(ddr2_regs->start, len);
-       if (!ddr2_reg_base) {
-               ret = -ENOMEM;
-               goto ioremap_fail;
-       }
+       ddr2_reg_base = pdata->ddr2_ctlr_base;
 
        ret = cpuidle_register_driver(&davinci_idle_driver);
        if (ret) {
                dev_err(&pdev->dev, "failed to register driver\n");
-               goto driver_register_fail;
+               return ret;
        }
 
        /* Wait for interrupt state */
@@ -167,18 +146,11 @@ static int __init davinci_cpuidle_probe(struct platform_device *pdev)
        ret = cpuidle_register_device(device);
        if (ret) {
                dev_err(&pdev->dev, "failed to register device\n");
-               goto device_register_fail;
+               cpuidle_unregister_driver(&davinci_idle_driver);
+               return ret;
        }
 
        return 0;
-
-device_register_fail:
-       cpuidle_unregister_driver(&davinci_idle_driver);
-driver_register_fail:
-       iounmap(ddr2_reg_base);
-ioremap_fail:
-       release_mem_region(ddr2_regs->start, len);
-       return ret;
 }
 
 static struct platform_driver davinci_cpuidle_driver = {
index b22b5cf04250c357b7cac71ebf7e32cde70a4658..122e61a9f505a6e3142a8a203c765f879ad53802 100644 (file)
@@ -371,7 +371,7 @@ static struct clk rmii_clk = {
        .parent         = &pll0_sysclk7,
 };
 
-static struct davinci_clk da830_clks[] = {
+static struct clk_lookup da830_clks[] = {
        CLK(NULL,               "ref",          &ref_clk),
        CLK(NULL,               "pll0",         &pll0_clk),
        CLK(NULL,               "pll0_aux",     &pll0_aux_clk),
@@ -1208,13 +1208,13 @@ static struct davinci_soc_info davinci_soc_info_da830 = {
 
 void __init da830_init(void)
 {
-       da8xx_syscfg_base = ioremap(DA8XX_SYSCFG_BASE, SZ_4K);
-       if (WARN(!da8xx_syscfg_base, "Unable to map syscfg module"))
+       da8xx_syscfg0_base = ioremap(DA8XX_SYSCFG0_BASE, SZ_4K);
+       if (WARN(!da8xx_syscfg0_base, "Unable to map syscfg0 module"))
                return;
 
        davinci_soc_info_da830.jtag_id_base =
-                                       DA8XX_SYSCFG_VIRT(DA8XX_JTAG_ID_REG);
-       davinci_soc_info_da830.pinmux_base = DA8XX_SYSCFG_VIRT(0x120);
+                                       DA8XX_SYSCFG0_VIRT(DA8XX_JTAG_ID_REG);
+       davinci_soc_info_da830.pinmux_base = DA8XX_SYSCFG0_VIRT(0x120);
 
        davinci_common_init(&davinci_soc_info_da830);
 }
index 717806c6cef942c3fdc5f65172d1643b2d706cfc..d0fd7566712a1ffb7983999a16b9d6600768dbd1 100644 (file)
@@ -26,6 +26,7 @@
 #include <mach/time.h>
 #include <mach/da8xx.h>
 #include <mach/cpufreq.h>
+#include <mach/pm.h>
 
 #include "clock.h"
 #include "mux.h"
@@ -40,6 +41,7 @@
 #define DA850_REF_FREQ         24000000
 
 #define CFGCHIP3_ASYNC3_CLKSRC BIT(4)
+#define CFGCHIP3_PLL1_MASTER_LOCK      BIT(5)
 #define CFGCHIP0_PLL_MASTER_LOCK       BIT(4)
 
 static int da850_set_armrate(struct clk *clk, unsigned long rate);
@@ -333,7 +335,7 @@ static struct clk aemif_clk = {
        .flags          = ALWAYS_ENABLED,
 };
 
-static struct davinci_clk da850_clks[] = {
+static struct clk_lookup da850_clks[] = {
        CLK(NULL,               "ref",          &ref_clk),
        CLK(NULL,               "pll0",         &pll0_clk),
        CLK(NULL,               "pll0_aux",     &pll0_aux_clk),
@@ -535,6 +537,7 @@ static const struct mux_config da850_pins[] = {
        MUX_CFG(DA850, GPIO2_15,        5,      0,      15,     8,      false)
        MUX_CFG(DA850, GPIO4_0,         10,     28,     15,     8,      false)
        MUX_CFG(DA850, GPIO4_1,         10,     24,     15,     8,      false)
+       MUX_CFG(DA850, RTC_ALARM,       0,      28,     15,     2,      false)
 #endif
 };
 
@@ -770,6 +773,12 @@ static struct map_desc da850_io_desc[] = {
                .length         = DA8XX_CP_INTC_SIZE,
                .type           = MT_DEVICE
        },
+       {
+               .virtual        = SRAM_VIRT,
+               .pfn            = __phys_to_pfn(DA8XX_ARM_RAM_BASE),
+               .length         = SZ_8K,
+               .type           = MT_DEVICE
+       },
 };
 
 static void __iomem *da850_psc_bases[] = {
@@ -825,12 +834,12 @@ static struct davinci_timer_info da850_timer_info = {
 static void da850_set_async3_src(int pllnum)
 {
        struct clk *clk, *newparent = pllnum ? &pll1_sysclk2 : &pll0_sysclk2;
-       struct davinci_clk *c;
+       struct clk_lookup *c;
        unsigned int v;
        int ret;
 
-       for (c = da850_clks; c->lk.clk; c++) {
-               clk = c->lk.clk;
+       for (c = da850_clks; c->clk; c++) {
+               clk = c->clk;
                if (clk->flags & DA850_CLK_ASYNC3) {
                        ret = clk_set_parent(clk, newparent);
                        WARN(ret, "DA850: unable to re-parent clock %s",
@@ -838,12 +847,12 @@ static void da850_set_async3_src(int pllnum)
                }
        }
 
-       v = __raw_readl(DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP3_REG));
+       v = __raw_readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP3_REG));
        if (pllnum)
                v |= CFGCHIP3_ASYNC3_CLKSRC;
        else
                v &= ~CFGCHIP3_ASYNC3_CLKSRC;
-       __raw_writel(v, DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP3_REG));
+       __raw_writel(v, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP3_REG));
 }
 
 #ifdef CONFIG_CPU_FREQ
@@ -987,7 +996,6 @@ static int da850_set_pll0rate(struct clk *clk, unsigned long index)
        unsigned int prediv, mult, postdiv;
        struct da850_opp *opp;
        struct pll_data *pll = clk->pll_data;
-       unsigned int v;
        int ret;
 
        opp = (struct da850_opp *) da850_freq_table[index].index;
@@ -995,11 +1003,6 @@ static int da850_set_pll0rate(struct clk *clk, unsigned long index)
        mult = opp->mult;
        postdiv = opp->postdiv;
 
-       /* Unlock writing to PLL registers */
-       v = __raw_readl(DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP0_REG));
-       v &= ~CFGCHIP0_PLL_MASTER_LOCK;
-       __raw_writel(v, DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP0_REG));
-
        ret = davinci_set_pllrate(pll, prediv, mult, postdiv);
        if (WARN_ON(ret))
                return ret;
@@ -1028,6 +1031,43 @@ static int da850_round_armrate(struct clk *clk, unsigned long rate)
 }
 #endif
 
+int da850_register_pm(struct platform_device *pdev)
+{
+       int ret;
+       struct davinci_pm_config *pdata = pdev->dev.platform_data;
+
+       ret = davinci_cfg_reg(DA850_RTC_ALARM);
+       if (ret)
+               return ret;
+
+       pdata->ddr2_ctlr_base = da8xx_get_mem_ctlr();
+       pdata->deepsleep_reg = DA8XX_SYSCFG1_VIRT(DA8XX_DEEPSLEEP_REG);
+       pdata->ddrpsc_num = DA8XX_LPSC1_EMIF3C;
+
+       pdata->cpupll_reg_base = ioremap(DA8XX_PLL0_BASE, SZ_4K);
+       if (!pdata->cpupll_reg_base)
+               return -ENOMEM;
+
+       pdata->ddrpll_reg_base = ioremap(DA8XX_PLL1_BASE, SZ_4K);
+       if (!pdata->ddrpll_reg_base) {
+               ret = -ENOMEM;
+               goto no_ddrpll_mem;
+       }
+
+       pdata->ddrpsc_reg_base = ioremap(DA8XX_PSC1_BASE, SZ_4K);
+       if (!pdata->ddrpsc_reg_base) {
+               ret = -ENOMEM;
+               goto no_ddrpsc_mem;
+       }
+
+       return platform_device_register(pdev);
+
+no_ddrpsc_mem:
+       iounmap(pdata->ddrpll_reg_base);
+no_ddrpll_mem:
+       iounmap(pdata->cpupll_reg_base);
+       return ret;
+}
 
 static struct davinci_soc_info davinci_soc_info_da850 = {
        .io_desc                = da850_io_desc,
@@ -1049,17 +1089,25 @@ static struct davinci_soc_info davinci_soc_info_da850 = {
        .gpio_irq               = IRQ_DA8XX_GPIO0,
        .serial_dev             = &da8xx_serial_device,
        .emac_pdata             = &da8xx_emac_pdata,
+       .sram_dma               = DA8XX_ARM_RAM_BASE,
+       .sram_len               = SZ_8K,
 };
 
 void __init da850_init(void)
 {
-       da8xx_syscfg_base = ioremap(DA8XX_SYSCFG_BASE, SZ_4K);
-       if (WARN(!da8xx_syscfg_base, "Unable to map syscfg module"))
+       unsigned int v;
+
+       da8xx_syscfg0_base = ioremap(DA8XX_SYSCFG0_BASE, SZ_4K);
+       if (WARN(!da8xx_syscfg0_base, "Unable to map syscfg0 module"))
+               return;
+
+       da8xx_syscfg1_base = ioremap(DA8XX_SYSCFG1_BASE, SZ_4K);
+       if (WARN(!da8xx_syscfg1_base, "Unable to map syscfg1 module"))
                return;
 
        davinci_soc_info_da850.jtag_id_base =
-                                       DA8XX_SYSCFG_VIRT(DA8XX_JTAG_ID_REG);
-       davinci_soc_info_da850.pinmux_base = DA8XX_SYSCFG_VIRT(0x120);
+                                       DA8XX_SYSCFG0_VIRT(DA8XX_JTAG_ID_REG);
+       davinci_soc_info_da850.pinmux_base = DA8XX_SYSCFG0_VIRT(0x120);
 
        davinci_common_init(&davinci_soc_info_da850);
 
@@ -1071,4 +1119,14 @@ void __init da850_init(void)
         * be any noticible change even in non-DVFS use cases.
         */
        da850_set_async3_src(1);
+
+       /* Unlock writing to PLL0 registers */
+       v = __raw_readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP0_REG));
+       v &= ~CFGCHIP0_PLL_MASTER_LOCK;
+       __raw_writel(v, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP0_REG));
+
+       /* Unlock writing to PLL1 registers */
+       v = __raw_readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP3_REG));
+       v &= ~CFGCHIP3_PLL1_MASTER_LOCK;
+       __raw_writel(v, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP3_REG));
 }
index a5105f03fd866055de3205a36ae18d8b30cf733c..0a96791d3b0f6dd8238c4e0826f3f452b3905477 100644 (file)
 #include "clock.h"
 
 #define DA8XX_TPCC_BASE                        0x01c00000
+#define DA850_TPCC1_BASE               0x01e30000
 #define DA8XX_TPTC0_BASE               0x01c08000
 #define DA8XX_TPTC1_BASE               0x01c08400
+#define DA850_TPTC2_BASE               0x01e38000
 #define DA8XX_WDOG_BASE                        0x01c21000 /* DA8XX_TIMER64P1_BASE */
 #define DA8XX_I2C0_BASE                        0x01c22000
 #define DA8XX_RTC_BASE                 0x01C23000
@@ -42,7 +44,8 @@
 #define DA8XX_MDIO_REG_OFFSET          0x4000
 #define DA8XX_EMAC_CTRL_RAM_SIZE       SZ_8K
 
-void __iomem *da8xx_syscfg_base;
+void __iomem *da8xx_syscfg0_base;
+void __iomem *da8xx_syscfg1_base;
 
 static struct plat_serial8250_port da8xx_serial_pdata[] = {
        {
@@ -82,11 +85,6 @@ struct platform_device da8xx_serial_device = {
        },
 };
 
-static const s8 da8xx_dma_chan_no_event[] = {
-       20, 21,
-       -1
-};
-
 static const s8 da8xx_queue_tc_mapping[][2] = {
        /* {event queue no, TC no} */
        {0, 0},
@@ -101,20 +99,52 @@ static const s8 da8xx_queue_priority_mapping[][2] = {
        {-1, -1}
 };
 
-static struct edma_soc_info da8xx_edma_info[] = {
+static const s8 da850_queue_tc_mapping[][2] = {
+       /* {event queue no, TC no} */
+       {0, 0},
+       {-1, -1}
+};
+
+static const s8 da850_queue_priority_mapping[][2] = {
+       /* {event queue no, Priority} */
+       {0, 3},
+       {-1, -1}
+};
+
+static struct edma_soc_info da830_edma_info[] = {
        {
                .n_channel              = 32,
                .n_region               = 4,
                .n_slot                 = 128,
                .n_tc                   = 2,
                .n_cc                   = 1,
-               .noevent                = da8xx_dma_chan_no_event,
                .queue_tc_mapping       = da8xx_queue_tc_mapping,
                .queue_priority_mapping = da8xx_queue_priority_mapping,
        },
 };
 
-static struct resource da8xx_edma_resources[] = {
+static struct edma_soc_info da850_edma_info[] = {
+       {
+               .n_channel              = 32,
+               .n_region               = 4,
+               .n_slot                 = 128,
+               .n_tc                   = 2,
+               .n_cc                   = 1,
+               .queue_tc_mapping       = da8xx_queue_tc_mapping,
+               .queue_priority_mapping = da8xx_queue_priority_mapping,
+       },
+       {
+               .n_channel              = 32,
+               .n_region               = 4,
+               .n_slot                 = 128,
+               .n_tc                   = 1,
+               .n_cc                   = 1,
+               .queue_tc_mapping       = da850_queue_tc_mapping,
+               .queue_priority_mapping = da850_queue_priority_mapping,
+       },
+};
+
+static struct resource da830_edma_resources[] = {
        {
                .name   = "edma_cc0",
                .start  = DA8XX_TPCC_BASE,
@@ -145,19 +175,91 @@ static struct resource da8xx_edma_resources[] = {
        },
 };
 
-static struct platform_device da8xx_edma_device = {
+static struct resource da850_edma_resources[] = {
+       {
+               .name   = "edma_cc0",
+               .start  = DA8XX_TPCC_BASE,
+               .end    = DA8XX_TPCC_BASE + SZ_32K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .name   = "edma_tc0",
+               .start  = DA8XX_TPTC0_BASE,
+               .end    = DA8XX_TPTC0_BASE + SZ_1K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .name   = "edma_tc1",
+               .start  = DA8XX_TPTC1_BASE,
+               .end    = DA8XX_TPTC1_BASE + SZ_1K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .name   = "edma_cc1",
+               .start  = DA850_TPCC1_BASE,
+               .end    = DA850_TPCC1_BASE + SZ_32K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .name   = "edma_tc2",
+               .start  = DA850_TPTC2_BASE,
+               .end    = DA850_TPTC2_BASE + SZ_1K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .name   = "edma0",
+               .start  = IRQ_DA8XX_CCINT0,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .name   = "edma0_err",
+               .start  = IRQ_DA8XX_CCERRINT,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .name   = "edma1",
+               .start  = IRQ_DA850_CCINT1,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .name   = "edma1_err",
+               .start  = IRQ_DA850_CCERRINT1,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device da830_edma_device = {
        .name           = "edma",
        .id             = -1,
        .dev = {
-               .platform_data  = da8xx_edma_info,
+               .platform_data = da830_edma_info,
        },
-       .num_resources  = ARRAY_SIZE(da8xx_edma_resources),
-       .resource       = da8xx_edma_resources,
+       .num_resources  = ARRAY_SIZE(da830_edma_resources),
+       .resource       = da830_edma_resources,
+};
+
+static struct platform_device da850_edma_device = {
+       .name           = "edma",
+       .id             = -1,
+       .dev = {
+               .platform_data = da850_edma_info,
+       },
+       .num_resources  = ARRAY_SIZE(da850_edma_resources),
+       .resource       = da850_edma_resources,
 };
 
 int __init da8xx_register_edma(void)
 {
-       return platform_device_register(&da8xx_edma_device);
+       struct platform_device *pdev;
+
+       if (cpu_is_davinci_da830())
+               pdev = &da830_edma_device;
+       else if (cpu_is_davinci_da850())
+               pdev = &da850_edma_device;
+       else
+               return -ENODEV;
+
+       return platform_device_register(pdev);
 }
 
 static struct resource da8xx_i2c_resources0[] = {
@@ -495,6 +597,19 @@ int da8xx_register_rtc(void)
        return ret;
 }
 
+static void __iomem *da8xx_ddr2_ctlr_base;
+void __iomem * __init da8xx_get_mem_ctlr(void)
+{
+       if (da8xx_ddr2_ctlr_base)
+               return da8xx_ddr2_ctlr_base;
+
+       da8xx_ddr2_ctlr_base = ioremap(DA8XX_DDR2_CTL_BASE, SZ_32K);
+       if (!da8xx_ddr2_ctlr_base)
+               pr_warning("%s: Unable to map DDR2 controller", __func__);
+
+       return da8xx_ddr2_ctlr_base;
+}
+
 static struct resource da8xx_cpuidle_resources[] = {
        {
                .start          = DA8XX_DDR2_CTL_BASE,
@@ -520,6 +635,7 @@ static struct platform_device da8xx_cpuidle_device = {
 
 int __init da8xx_register_cpuidle(void)
 {
+       da8xx_cpuidle_pdata.ddr2_ctlr_base = da8xx_get_mem_ctlr();
+
        return platform_device_register(&da8xx_cpuidle_device);
 }
-
index d84e85414d20d9c4a098e97459b22b2f254d3371..3dc0a88712eb988041c8f951e076df67529a9422 100644 (file)
@@ -29,6 +29,7 @@
 #include <mach/serial.h>
 #include <mach/common.h>
 #include <mach/asp.h>
+#include <mach/spi.h>
 
 #include "clock.h"
 #include "mux.h"
@@ -334,7 +335,7 @@ static struct clk usb_clk = {
        .lpsc = DAVINCI_LPSC_USB,
 };
 
-static struct davinci_clk dm355_clks[] = {
+static struct clk_lookup dm355_clks[] = {
        CLK(NULL, "ref", &ref_clk),
        CLK(NULL, "pll1", &pll1_clk),
        CLK(NULL, "pll1_sysclk1", &pll1_sysclk1),
@@ -362,9 +363,9 @@ static struct davinci_clk dm355_clks[] = {
        CLK("davinci-asp.1", NULL, &asp1_clk),
        CLK("davinci_mmc.0", NULL, &mmcsd0_clk),
        CLK("davinci_mmc.1", NULL, &mmcsd1_clk),
-       CLK(NULL, "spi0", &spi0_clk),
-       CLK(NULL, "spi1", &spi1_clk),
-       CLK(NULL, "spi2", &spi2_clk),
+       CLK("spi_davinci.0", NULL, &spi0_clk),
+       CLK("spi_davinci.1", NULL, &spi1_clk),
+       CLK("spi_davinci.2", NULL, &spi2_clk),
        CLK(NULL, "gpio", &gpio_clk),
        CLK(NULL, "aemif", &aemif_clk),
        CLK(NULL, "pwm0", &pwm0_clk),
@@ -391,24 +392,40 @@ static struct resource dm355_spi0_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
-               .start = IRQ_DM355_SPINT0_1,
+               .start = IRQ_DM355_SPINT0_0,
                .flags = IORESOURCE_IRQ,
        },
-       /* Not yet used, so not included:
-        * IORESOURCE_IRQ:
-        *  - IRQ_DM355_SPINT0_0
-        * IORESOURCE_DMA:
-        *  - DAVINCI_DMA_SPI_SPIX
-        *  - DAVINCI_DMA_SPI_SPIR
-        */
+       {
+               .start = 17,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = 16,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = EVENTQ_1,
+               .flags = IORESOURCE_DMA,
+       },
 };
 
+static struct davinci_spi_platform_data dm355_spi0_pdata = {
+       .version        = SPI_VERSION_1,
+       .num_chipselect = 2,
+       .clk_internal   = 1,
+       .cs_hold        = 1,
+       .intr_level     = 0,
+       .poll_mode      = 1,    /* 0 -> interrupt mode 1-> polling mode */
+       .c2tdelay       = 0,
+       .t2cdelay       = 0,
+};
 static struct platform_device dm355_spi0_device = {
        .name = "spi_davinci",
        .id = 0,
        .dev = {
                .dma_mask = &dm355_spi0_dma_mask,
                .coherent_dma_mask = DMA_BIT_MASK(32),
+               .platform_data = &dm355_spi0_pdata,
        },
        .num_resources = ARRAY_SIZE(dm355_spi0_resources),
        .resource = dm355_spi0_resources,
@@ -563,13 +580,6 @@ static u8 dm355_default_priorities[DAVINCI_N_AINTC_IRQ] = {
 
 /*----------------------------------------------------------------------*/
 
-static const s8 dma_chan_dm355_no_event[] = {
-       12, 13, 24, 56, 57,
-       58, 59, 60, 61, 62,
-       63,
-       -1
-};
-
 static const s8
 queue_tc_mapping[][2] = {
        /* {event queue no, TC no} */
@@ -593,7 +603,6 @@ static struct edma_soc_info dm355_edma_info[] = {
                .n_slot                 = 128,
                .n_tc                   = 2,
                .n_cc                   = 1,
-               .noevent                = dma_chan_dm355_no_event,
                .queue_tc_mapping       = queue_tc_mapping,
                .queue_priority_mapping = queue_priority_mapping,
        },
index ce9da43a628b91c9a471359976ee03d05c4a786d..27772e18e45b948014b18e6294e08eaee1846afb 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/gpio.h>
+#include <linux/spi/spi.h>
 
 #include <asm/mach/map.h>
 
@@ -32,6 +33,8 @@
 #include <mach/common.h>
 #include <mach/asp.h>
 #include <mach/keyscan.h>
+#include <mach/spi.h>
+
 
 #include "clock.h"
 #include "mux.h"
@@ -403,7 +406,7 @@ static struct clk mjcp_clk = {
        .lpsc           = DM365_LPSC_MJCP,
 };
 
-static struct davinci_clk dm365_clks[] = {
+static struct clk_lookup dm365_clks[] = {
        CLK(NULL, "ref", &ref_clk),
        CLK(NULL, "pll1", &pll1_clk),
        CLK(NULL, "pll1_aux", &pll1_aux_clk),
@@ -455,7 +458,7 @@ static struct davinci_clk dm365_clks[] = {
        CLK(NULL, "timer3", &timer3_clk),
        CLK(NULL, "usb", &usb_clk),
        CLK("davinci_emac.1", NULL, &emac_clk),
-       CLK("voice_codec", NULL, &voicecodec_clk),
+       CLK("davinci_voicecodec", NULL, &voicecodec_clk),
        CLK("davinci-asp.0", NULL, &asp0_clk),
        CLK(NULL, "rto", &rto_clk),
        CLK(NULL, "mjcp", &mjcp_clk),
@@ -606,9 +609,78 @@ INT_CFG(DM365,  INT_NSF_DISABLE,     25,    1,    0,     false)
 
 EVT_CFG(DM365, EVT2_ASP_TX,         0,     1,    0,     false)
 EVT_CFG(DM365, EVT3_ASP_RX,         1,     1,    0,     false)
+EVT_CFG(DM365, EVT2_VC_TX,          0,     1,    1,     false)
+EVT_CFG(DM365, EVT3_VC_RX,          1,     1,    1,     false)
 #endif
 };
 
+static u64 dm365_spi0_dma_mask = DMA_BIT_MASK(32);
+
+static struct davinci_spi_platform_data dm365_spi0_pdata = {
+       .version        = SPI_VERSION_1,
+       .num_chipselect = 2,
+       .clk_internal   = 1,
+       .cs_hold        = 1,
+       .intr_level     = 0,
+       .poll_mode      = 1,    /* 0 -> interrupt mode 1-> polling mode */
+       .c2tdelay       = 0,
+       .t2cdelay       = 0,
+};
+
+static struct resource dm365_spi0_resources[] = {
+       {
+               .start = 0x01c66000,
+               .end   = 0x01c667ff,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_DM365_SPIINT0_0,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = 17,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = 16,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = EVENTQ_3,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+static struct platform_device dm365_spi0_device = {
+       .name = "spi_davinci",
+       .id = 0,
+       .dev = {
+               .dma_mask = &dm365_spi0_dma_mask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
+               .platform_data = &dm365_spi0_pdata,
+       },
+       .num_resources = ARRAY_SIZE(dm365_spi0_resources),
+       .resource = dm365_spi0_resources,
+};
+
+void __init dm365_init_spi0(unsigned chipselect_mask,
+               struct spi_board_info *info, unsigned len)
+{
+       davinci_cfg_reg(DM365_SPI0_SCLK);
+       davinci_cfg_reg(DM365_SPI0_SDI);
+       davinci_cfg_reg(DM365_SPI0_SDO);
+
+       /* not all slaves will be wired up */
+       if (chipselect_mask & BIT(0))
+               davinci_cfg_reg(DM365_SPI0_SDENA0);
+       if (chipselect_mask & BIT(1))
+               davinci_cfg_reg(DM365_SPI0_SDENA1);
+
+       spi_register_board_info(info, len);
+
+       platform_device_register(&dm365_spi0_device);
+}
+
 static struct emac_platform_data dm365_emac_pdata = {
        .ctrl_reg_offset        = DM365_EMAC_CNTRL_OFFSET,
        .ctrl_mod_reg_offset    = DM365_EMAC_CNTRL_MOD_OFFSET,
@@ -754,7 +826,7 @@ static struct edma_soc_info dm365_edma_info[] = {
                .n_cc                   = 1,
                .queue_tc_mapping       = dm365_queue_tc_mapping,
                .queue_priority_mapping = dm365_queue_priority_mapping,
-               .default_queue          = EVENTQ_2,
+               .default_queue          = EVENTQ_3,
        },
 };
 
@@ -835,6 +907,31 @@ static struct platform_device dm365_asp_device = {
        .resource       = dm365_asp_resources,
 };
 
+static struct resource dm365_vc_resources[] = {
+       {
+               .start  = DAVINCI_DM365_VC_BASE,
+               .end    = DAVINCI_DM365_VC_BASE + SZ_1K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = DAVINCI_DMA_VC_TX,
+               .end    = DAVINCI_DMA_VC_TX,
+               .flags  = IORESOURCE_DMA,
+       },
+       {
+               .start  = DAVINCI_DMA_VC_RX,
+               .end    = DAVINCI_DMA_VC_RX,
+               .flags  = IORESOURCE_DMA,
+       },
+};
+
+static struct platform_device dm365_vc_device = {
+       .name           = "davinci_voicecodec",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(dm365_vc_resources),
+       .resource       = dm365_vc_resources,
+};
+
 static struct resource dm365_rtc_resources[] = {
        {
                .start = DM365_RTC_BASE,
@@ -991,6 +1088,14 @@ void __init dm365_init_asp(struct snd_platform_data *pdata)
        platform_device_register(&dm365_asp_device);
 }
 
+void __init dm365_init_vc(struct snd_platform_data *pdata)
+{
+       davinci_cfg_reg(DM365_EVT2_VC_TX);
+       davinci_cfg_reg(DM365_EVT3_VC_RX);
+       dm365_vc_device.dev.platform_data = pdata;
+       platform_device_register(&dm365_vc_device);
+}
+
 void __init dm365_init_ks(struct davinci_ks_platform_data *pdata)
 {
        dm365_ks_device.dev.platform_data = pdata;
index 92aeb560068010b126cf8bd08390d7ead77c584e..2f2ae8bc77bb80b00ca46436142b83f0b3d7df9c 100644 (file)
@@ -277,7 +277,7 @@ static struct clk timer2_clk = {
        .usecount = 1,              /* REVISIT: why cant' this be disabled? */
 };
 
-struct davinci_clk dm644x_clks[] = {
+struct clk_lookup dm644x_clks[] = {
        CLK(NULL, "ref", &ref_clk),
        CLK(NULL, "pll1", &pll1_clk),
        CLK(NULL, "pll1_sysclk1", &pll1_sysclk1),
@@ -479,15 +479,6 @@ static u8 dm644x_default_priorities[DAVINCI_N_AINTC_IRQ] = {
 
 /*----------------------------------------------------------------------*/
 
-static const s8 dma_chan_dm644x_no_event[] = {
-        0,  1, 12, 13, 14,
-       15, 25, 30, 31, 45,
-       46, 47, 55, 56, 57,
-       58, 59, 60, 61, 62,
-       63,
-       -1
-};
-
 static const s8
 queue_tc_mapping[][2] = {
        /* {event queue no, TC no} */
@@ -511,7 +502,6 @@ static struct edma_soc_info dm644x_edma_info[] = {
                .n_slot                 = 128,
                .n_tc                   = 2,
                .n_cc                   = 1,
-               .noevent                = dma_chan_dm644x_no_event,
                .queue_tc_mapping       = queue_tc_mapping,
                .queue_priority_mapping = queue_priority_mapping,
        },
index 829a44bcf7994e9242e0e56a0463be5c3071e59e..893baf4ad37dc45bda883026a7eb7b3d73012097 100644 (file)
@@ -42,7 +42,6 @@
 /*
  * Device specific clocks
  */
-#define DM646X_REF_FREQ                27000000
 #define DM646X_AUX_FREQ                24000000
 
 static struct pll_data pll1_data = {
@@ -57,7 +56,6 @@ static struct pll_data pll2_data = {
 
 static struct clk ref_clk = {
        .name = "ref_clk",
-       .rate = DM646X_REF_FREQ,
 };
 
 static struct clk aux_clkin = {
@@ -313,7 +311,7 @@ static struct clk vpif1_clk = {
        .flags = ALWAYS_ENABLED,
 };
 
-struct davinci_clk dm646x_clks[] = {
+struct clk_lookup dm646x_clks[] = {
        CLK(NULL, "ref", &ref_clk),
        CLK(NULL, "aux", &aux_clkin),
        CLK(NULL, "pll1", &pll1_clk),
@@ -513,14 +511,6 @@ static u8 dm646x_default_priorities[DAVINCI_N_AINTC_IRQ] = {
 
 /*----------------------------------------------------------------------*/
 
-static const s8 dma_chan_dm646x_no_event[] = {
-        0,  1,  2,  3, 13,
-       14, 15, 24, 25, 26,
-       27, 30, 31, 54, 55,
-       56,
-       -1
-};
-
 /* Four Transfer Controllers on DM646x */
 static const s8
 dm646x_queue_tc_mapping[][2] = {
@@ -549,7 +539,6 @@ static struct edma_soc_info dm646x_edma_info[] = {
                .n_slot                 = 512,
                .n_tc                   = 4,
                .n_cc                   = 1,
-               .noevent                = dma_chan_dm646x_no_event,
                .queue_tc_mapping       = dm646x_queue_tc_mapping,
                .queue_priority_mapping = dm646x_queue_priority_mapping,
        },
@@ -925,6 +914,7 @@ void dm646x_setup_vpif(struct vpif_display_config *display_config,
 
 void __init dm646x_init(void)
 {
+       dm646x_board_setup_refclk(&ref_clk);
        davinci_common_init(&davinci_soc_info_dm646x);
 }
 
index 648fbb760ae1d63c74e700eae260629046add8b1..15dd886df04ca08cec53abb11ed9a6105a3a81c8 100644 (file)
@@ -226,11 +226,11 @@ struct edma {
         */
        DECLARE_BITMAP(edma_inuse, EDMA_MAX_PARAMENTRY);
 
-       /* The edma_noevent bit for each channel is clear unless
-        * it doesn't trigger DMA events on this platform.  It uses a
-        * bit of SOC-specific initialization code.
+       /* The edma_unused bit for each channel is clear unless
+        * it is not being used on this platform. It uses a bit
+        * of SOC-specific initialization code.
         */
-       DECLARE_BITMAP(edma_noevent, EDMA_MAX_DMACH);
+       DECLARE_BITMAP(edma_unused, EDMA_MAX_DMACH);
 
        unsigned        irq_res_start;
        unsigned        irq_res_end;
@@ -243,6 +243,7 @@ struct edma {
 };
 
 static struct edma *edma_info[EDMA_MAX_CC];
+static int arch_num_cc;
 
 /* dummy param set used to (re)initialize parameter RAM slots */
 static const struct edmacc_param dummy_paramset = {
@@ -555,8 +556,27 @@ static int reserve_contiguous_slots(int ctlr, unsigned int id,
        return EDMA_CTLR_CHAN(ctlr, i - num_slots + 1);
 }
 
+static int prepare_unused_channel_list(struct device *dev, void *data)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       int i, ctlr;
+
+       for (i = 0; i < pdev->num_resources; i++) {
+               if ((pdev->resource[i].flags & IORESOURCE_DMA) &&
+                               (int)pdev->resource[i].start >= 0) {
+                       ctlr = EDMA_CTLR(pdev->resource[i].start);
+                       clear_bit(EDMA_CHAN_SLOT(pdev->resource[i].start),
+                                       edma_info[ctlr]->edma_unused);
+               }
+       }
+
+       return 0;
+}
+
 /*-----------------------------------------------------------------------*/
 
+static bool unused_chan_list_done;
+
 /* Resource alloc/free:  dma channels, parameter RAM slots */
 
 /**
@@ -594,7 +614,22 @@ int edma_alloc_channel(int channel,
                void *data,
                enum dma_event_q eventq_no)
 {
-       unsigned i, done, ctlr = 0;
+       unsigned i, done = 0, ctlr = 0;
+       int ret = 0;
+
+       if (!unused_chan_list_done) {
+               /*
+                * Scan all the platform devices to find out the EDMA channels
+                * used and clear them in the unused list, making the rest
+                * available for ARM usage.
+                */
+               ret = bus_for_each_dev(&platform_bus_type, NULL, NULL,
+                               prepare_unused_channel_list);
+               if (ret < 0)
+                       return ret;
+
+               unused_chan_list_done = true;
+       }
 
        if (channel >= 0) {
                ctlr = EDMA_CTLR(channel);
@@ -602,15 +637,15 @@ int edma_alloc_channel(int channel,
        }
 
        if (channel < 0) {
-               for (i = 0; i < EDMA_MAX_CC; i++) {
+               for (i = 0; i < arch_num_cc; i++) {
                        channel = 0;
                        for (;;) {
                                channel = find_next_bit(edma_info[i]->
-                                               edma_noevent,
+                                               edma_unused,
                                                edma_info[i]->num_channels,
                                                channel);
                                if (channel == edma_info[i]->num_channels)
-                                       return -ENOMEM;
+                                       break;
                                if (!test_and_set_bit(channel,
                                                edma_info[i]->edma_inuse)) {
                                        done = 1;
@@ -622,6 +657,8 @@ int edma_alloc_channel(int channel,
                        if (done)
                                break;
                }
+               if (!done)
+                       return -ENOMEM;
        } else if (channel >= edma_info[ctlr]->num_channels) {
                return -EINVAL;
        } else if (test_and_set_bit(channel, edma_info[ctlr]->edma_inuse)) {
@@ -642,7 +679,7 @@ int edma_alloc_channel(int channel,
 
        map_dmach_queue(ctlr, channel, eventq_no);
 
-       return channel;
+       return EDMA_CTLR_CHAN(ctlr, channel);
 }
 EXPORT_SYMBOL(edma_alloc_channel);
 
@@ -1219,7 +1256,7 @@ int edma_start(unsigned channel)
                unsigned int mask = (1 << (channel & 0x1f));
 
                /* EDMA channels without event association */
-               if (test_bit(channel, edma_info[ctlr]->edma_noevent)) {
+               if (test_bit(channel, edma_info[ctlr]->edma_unused)) {
                        pr_debug("EDMA: ESR%d %08x\n", j,
                                edma_shadow0_read_array(ctlr, SH_ESR, j));
                        edma_shadow0_write_array(ctlr, SH_ESR, j, mask);
@@ -1344,7 +1381,6 @@ static int __init edma_probe(struct platform_device *pdev)
        const s8                (*queue_tc_mapping)[2];
        int                     i, j, found = 0;
        int                     status = -1;
-       const s8                *noevent;
        int                     irq[EDMA_MAX_CC] = {0, 0};
        int                     err_irq[EDMA_MAX_CC] = {0, 0};
        struct resource         *r[EDMA_MAX_CC] = {NULL};
@@ -1407,11 +1443,9 @@ static int __init edma_probe(struct platform_device *pdev)
                        memcpy_toio(edmacc_regs_base[j] + PARM_OFFSET(i),
                                        &dummy_paramset, PARM_SIZE);
 
-               noevent = info[j].noevent;
-               if (noevent) {
-                       while (*noevent != -1)
-                               set_bit(*noevent++, edma_info[j]->edma_noevent);
-               }
+               /* Mark all channels as unused */
+               memset(edma_info[j]->edma_unused, 0xff,
+                       sizeof(edma_info[j]->edma_unused));
 
                sprintf(irq_name, "edma%d", j);
                irq[j] = platform_get_irq_byname(pdev, irq_name);
@@ -1467,6 +1501,7 @@ static int __init edma_probe(struct platform_device *pdev)
                        edma_write_array2(j, EDMA_DRAE, i, 1, 0x0);
                        edma_write_array(j, EDMA_QRAE, i, 0x0);
                }
+               arch_num_cc++;
        }
 
        if (tc_errs_handled) {
diff --git a/arch/arm/mach-davinci/include/mach/cdce949.h b/arch/arm/mach-davinci/include/mach/cdce949.h
new file mode 100644 (file)
index 0000000..c73331f
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * TI CDCE949 off-chip clock synthesizer support
+ *
+ * 2009 (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_CDCE949_H
+#define _MACH_DAVINCI_CDCE949_H
+
+#include <linux/clk.h>
+
+#include <mach/clock.h>
+
+int cdce_set_rate(struct clk *clk, unsigned long rate);
+
+#endif
index 6ca2c9a0a4827839c105d037e73ad5bb83a8b53c..50a955f05ef9e127b3a28d0b82d344b797521fd1 100644 (file)
@@ -43,7 +43,7 @@ struct davinci_soc_info {
        void __iomem                    *jtag_id_base;
        struct davinci_id               *ids;
        unsigned long                   ids_num;
-       struct davinci_clk              *cpu_clks;
+       struct clk_lookup               *cpu_clks;
        void __iomem                    **psc_bases;
        unsigned long                   psc_bases_num;
        void __iomem                    *pinmux_base;
index cbfc6a9c81b42d1d7bc2f3a1e53a7f6a9319fed9..74f088b0edfb0c141794833c34e9622d4357358a 100644 (file)
@@ -12,6 +12,7 @@
 
 struct davinci_cpuidle_config {
        u32 ddr2_pdown;
+       void __iomem *ddr2_ctlr_base;
 };
 
 #endif
index 90704910d343825e36a624dccd9991f0e7106029..cc9be7fee6273e8534296c146d76b39d0f3c3e44 100644 (file)
 
 #include <video/da8xx-fb.h>
 
+#include <linux/davinci_emac.h>
 #include <mach/serial.h>
 #include <mach/edma.h>
 #include <mach/i2c.h>
-#include <mach/emac.h>
 #include <mach/asp.h>
 #include <mach/mmc.h>
 #include <mach/usb.h>
+#include <mach/pm.h>
 
-extern void __iomem *da8xx_syscfg_base;
+extern void __iomem *da8xx_syscfg0_base;
+extern void __iomem *da8xx_syscfg1_base;
 
 /*
  * The cp_intc interrupt controller for the da8xx isn't in the same
@@ -34,13 +36,17 @@ extern void __iomem *da8xx_syscfg_base;
 #define DA8XX_CP_INTC_SIZE     SZ_8K
 #define DA8XX_CP_INTC_VIRT     (IO_VIRT - DA8XX_CP_INTC_SIZE - SZ_4K)
 
-#define DA8XX_SYSCFG_BASE      (IO_PHYS + 0x14000)
-#define DA8XX_SYSCFG_VIRT(x)   (da8xx_syscfg_base + (x))
+#define DA8XX_SYSCFG0_BASE     (IO_PHYS + 0x14000)
+#define DA8XX_SYSCFG0_VIRT(x)  (da8xx_syscfg0_base + (x))
 #define DA8XX_JTAG_ID_REG      0x18
 #define DA8XX_CFGCHIP0_REG     0x17c
 #define DA8XX_CFGCHIP2_REG     0x184
 #define DA8XX_CFGCHIP3_REG     0x188
 
+#define DA8XX_SYSCFG1_BASE     (IO_PHYS + 0x22C000)
+#define DA8XX_SYSCFG1_VIRT(x)  (da8xx_syscfg1_base + (x))
+#define DA8XX_DEEPSLEEP_REG    0x8
+
 #define DA8XX_PSC0_BASE                0x01c10000
 #define DA8XX_PLL0_BASE                0x01c11000
 #define DA8XX_TIMER64P0_BASE   0x01c20000
@@ -48,11 +54,13 @@ extern void __iomem *da8xx_syscfg_base;
 #define DA8XX_GPIO_BASE                0x01e26000
 #define DA8XX_PSC1_BASE                0x01e27000
 #define DA8XX_LCD_CNTRL_BASE   0x01e13000
+#define DA8XX_PLL1_BASE                0x01e1a000
 #define DA8XX_MMCSD0_BASE      0x01c40000
 #define DA8XX_AEMIF_CS2_BASE   0x60000000
 #define DA8XX_AEMIF_CS3_BASE   0x62000000
 #define DA8XX_AEMIF_CTL_BASE   0x68000000
 #define DA8XX_DDR2_CTL_BASE    0xb0000000
+#define DA8XX_ARM_RAM_BASE     0xffff0000
 
 #define PINMUX0                        0x00
 #define PINMUX1                        0x04
@@ -90,6 +98,8 @@ void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata);
 int da8xx_register_rtc(void);
 int da850_register_cpufreq(void);
 int da8xx_register_cpuidle(void);
+void __iomem * __init da8xx_get_mem_ctlr(void);
+int da850_register_pm(struct platform_device *pdev);
 
 extern struct platform_device da8xx_serial_device;
 extern struct emac_platform_data da8xx_emac_pdata;
index 17ab5236da6618af1a9ee2ebd32968692b050252..3cd93a801d9b94ba84689147d48c26e12df4ccfd 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/serial_reg.h>
 #define UART_SHIFT     2
 
-               .macro addruart, rx
+               .macro addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                 @ MMU enabled?
                moveq   \rx, #0x01000000        @ physical base address
index 9fc5a64a536424103361485102d32259e904f81c..3a37b5a6983ca034bd91bebf2a53a6ac3c0bff7e 100644 (file)
@@ -14,8 +14,8 @@
 #define __ASM_ARCH_DM665_H
 
 #include <linux/platform_device.h>
+#include <linux/davinci_emac.h>
 #include <mach/hardware.h>
-#include <mach/emac.h>
 #include <mach/asp.h>
 #include <mach/keyscan.h>
 #include <media/davinci/vpfe_capture.h>
 
 #define DM365_RTC_BASE                 (0x01C69000)
 
+#define DAVINCI_DM365_VC_BASE          (0x01D0C000)
+#define DAVINCI_DMA_VC_TX              2
+#define DAVINCI_DMA_VC_RX              3
+
 void __init dm365_init(void);
 void __init dm365_init_asp(struct snd_platform_data *pdata);
+void __init dm365_init_vc(struct snd_platform_data *pdata);
 void __init dm365_init_ks(struct davinci_ks_platform_data *pdata);
 void __init dm365_init_rtc(void);
+void dm365_init_spi0(unsigned chipselect_mask,
+                       struct spi_board_info *info, unsigned len);
 
 void dm365_set_vpfe_config(struct vpfe_config *cfg);
 #endif /* __ASM_ARCH_DM365_H */
index 44e8f0fae9ea2670f6333d5f35e1518b627728f8..1a8b09ccc3c8493bcf94a7001b9cc871a79afa43 100644 (file)
@@ -22,8 +22,8 @@
 #ifndef __ASM_ARCH_DM644X_H
 #define __ASM_ARCH_DM644X_H
 
+#include <linux/davinci_emac.h>
 #include <mach/hardware.h>
-#include <mach/emac.h>
 #include <mach/asp.h>
 #include <media/davinci/vpfe_capture.h>
 
index 8cec746ae9d218eb107567514fce90dd20e59046..846da98b619af4f41e56039520e92c6e5372a390 100644 (file)
 #define __ASM_ARCH_DM646X_H
 
 #include <mach/hardware.h>
-#include <mach/emac.h>
 #include <mach/asp.h>
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
+#include <linux/clk.h>
+#include <linux/davinci_emac.h>
 
 #define DM646X_EMAC_BASE               (0x01C80000)
 #define DM646X_EMAC_CNTRL_OFFSET       (0x0000)
@@ -30,6 +31,7 @@ void __init dm646x_init(void);
 void __init dm646x_init_ide(void);
 void __init dm646x_init_mcasp0(struct snd_platform_data *pdata);
 void __init dm646x_init_mcasp1(struct snd_platform_data *pdata);
+void __init dm646x_board_setup_refclk(struct clk *clk);
 
 void dm646x_video_init(void);
 
index eb8bfd7925e78cc49b163debac7a6149c8f10ad7..ced3092af5ba71dad30fa25e00373d0418e95e10 100644 (file)
@@ -280,8 +280,6 @@ struct edma_soc_info {
        unsigned        n_cc;
        enum dma_event_q        default_queue;
 
-       /* list of channels with no even trigger; terminated by "-1" */
-       const s8        *noevent;
        const s8        (*queue_tc_mapping)[2];
        const s8        (*queue_priority_mapping)[2];
 };
index 41c89386e39b46f416aa4c9e12ee6332364ce21b..c45ba1f62a11a3b32d70b44e291a1f0bc8b98764 100644 (file)
@@ -27,7 +27,7 @@
 /*
  * I/O mapping
  */
-#define IO_PHYS                                0x01c00000
+#define IO_PHYS                                0x01c00000UL
 #define IO_OFFSET                      0xfd000000 /* Virtual IO = 0xfec00000 */
 #define IO_SIZE                                0x00400000
 #define IO_VIRT                                (IO_PHYS + IO_OFFSET)
index c248e9b7e82517c619b0fe74db18c4d3e88a2797..39fdceac8414202a6dfa3327bc2f5fd535d3f0bb 100644 (file)
@@ -16,6 +16,8 @@
 struct davinci_i2c_platform_data {
        unsigned int    bus_freq;       /* standard bus frequency (kHz) */
        unsigned int    bus_delay;      /* post-transaction delay (usec) */
+       unsigned int    sda_pin;        /* GPIO pin ID to use for SDA */
+       unsigned int    scl_pin;        /* GPIO pin ID to use for SCL */
 };
 
 /* for board setup code */
index 80309aed534ab0f2073adf49a963cb48e36cb31a..a91edfb8beeac3109542989c957256436fd5a5c8 100644 (file)
 #define PHYS_OFFSET DAVINCI_DDR_BASE
 #endif
 
+#define DDR2_SDRCR_OFFSET      0xc
+#define DDR2_SRPD_BIT          BIT(23)
+#define DDR2_MCLKSTOPEN_BIT    BIT(30)
+#define DDR2_LPMODEN_BIT       BIT(31)
+
 /*
  * Increase size of DMA-consistent memory region
  */
index b60c693985ff13777ea7ba4503e572c42084a3db..2a68c1d8a24bc1e58a1db9a908818de235663574 100644 (file)
@@ -327,6 +327,8 @@ enum davinci_dm365_index {
        /* EDMA event muxing */
        DM365_EVT2_ASP_TX,
        DM365_EVT3_ASP_RX,
+       DM365_EVT2_VC_TX,
+       DM365_EVT3_VC_RX,
        DM365_EVT26_MMC0_RX,
 };
 
@@ -899,6 +901,7 @@ enum davinci_da850_index {
        DA850_GPIO2_15,
        DA850_GPIO4_0,
        DA850_GPIO4_1,
+       DA850_RTC_ALARM,
 };
 
 #ifdef CONFIG_DAVINCI_MUX
diff --git a/arch/arm/mach-davinci/include/mach/pm.h b/arch/arm/mach-davinci/include/mach/pm.h
new file mode 100644 (file)
index 0000000..37b19bf
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * TI DaVinci platform support for power management.
+ *
+ * Copyright (C) 2009 Texas Instruments, Inc. 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 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 _MACH_DAVINCI_PM_H
+#define _MACH_DAVINCI_PM_H
+
+/*
+ * Caution: Assembly code in sleep.S makes assumtion on the order
+ * of the members of this structure.
+ */
+struct davinci_pm_config {
+       void __iomem *ddr2_ctlr_base;
+       void __iomem *ddrpsc_reg_base;
+       int ddrpsc_num;
+       void __iomem *ddrpll_reg_base;
+       void __iomem *deepsleep_reg;
+       void __iomem *cpupll_reg_base;
+       /*
+        * Note on SLEEPCOUNT:
+        * The SLEEPCOUNT feature is mainly intended for cases in which
+        * the internal oscillator is used. The internal oscillator is
+        * fully disabled in deep sleep mode.  When you exist deep sleep
+        * mode, the oscillator will be turned on and will generate very
+        * small oscillations which will not be detected by the deep sleep
+        * counter.  Eventually those oscillations will grow to an amplitude
+        * large enough to start incrementing the deep sleep counter.
+        * In this case recommendation from hardware engineers is that the
+        * SLEEPCOUNT be set to 4096.  This means that 4096 valid clock cycles
+        * must be detected before the clock is passed to the rest of the
+        * system.
+        * In the case that the internal oscillator is not used and the
+        * clock is generated externally, the SLEEPCOUNT value can be very
+        * small since the clock input is assumed to be stable before SoC
+        * is taken out of deepsleep mode.  A value of 128 would be more than
+        * adequate.
+        */
+       int sleepcount;
+};
+
+extern unsigned int davinci_cpu_suspend_sz;
+extern void davinci_cpu_suspend(struct davinci_pm_config *);
+
+#endif
index 171173c1dbadd8bbef71ddee5d8a1d894c3d135c..651f6d8158faf01505eddb8cce9b2eaae2ce367c 100644 (file)
 #define DA8XX_LPSC1_CR_P3_SS           26
 #define DA8XX_LPSC1_L3_CBA_RAM         31
 
+/* PSC register offsets */
+#define EPCPR          0x070
+#define PTCMD          0x120
+#define PTSTAT         0x128
+#define PDSTAT         0x200
+#define PDCTL1         0x304
+#define MDSTAT         0x800
+#define MDCTL          0xA00
+
+#define MDSTAT_STATE_MASK 0x1f
+
+#ifndef __ASSEMBLER__
+
 extern int davinci_psc_is_clk_active(unsigned int ctlr, unsigned int id);
 extern void davinci_psc_config(unsigned int domain, unsigned int ctlr,
                unsigned int id, char enable);
 
+#endif
+
 #endif /* __ASM_ARCH_PSC_H */
diff --git a/arch/arm/mach-davinci/include/mach/spi.h b/arch/arm/mach-davinci/include/mach/spi.h
new file mode 100644 (file)
index 0000000..910efbf
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef __ARCH_ARM_DAVINCI_SPI_H
+#define __ARCH_ARM_DAVINCI_SPI_H
+
+enum {
+       SPI_VERSION_1, /* For DM355/DM365/DM6467 */
+       SPI_VERSION_2, /* For DA8xx */
+};
+
+struct davinci_spi_platform_data {
+       u8      version;
+       u8      num_chipselect;
+       u8      wdelay;
+       u8      odd_parity;
+       u8      parity_enable;
+       u8      wait_enable;
+       u8      timer_disable;
+       u8      clk_internal;
+       u8      cs_hold;
+       u8      intr_level;
+       u8      poll_mode;
+       u8      use_dma;
+       u8      c2tdelay;
+       u8      t2cdelay;
+};
+
+#endif /* __ARCH_ARM_DAVINCI_SPI_H */
index 52827567841d73c8f19c50f15821d8b785732020..9b885298f1061b357310705e82b23960961ac223 100644 (file)
 #ifndef __ASM_ARCH_TIMEX_H
 #define __ASM_ARCH_TIMEX_H
 
-/* The source frequency for the timers is the 27MHz clock */
+/*
+ * Alert: Not all timers of the DaVinci family run at a frequency of 27MHz,
+ * but we should be fine as long as CLOCK_TICK_RATE or LATCH (see include/
+ * linux/jiffies.h) are not used directly in code. Currently none of the
+ * code relevant to DaVinci platform depends on these values directly.
+ */
 #define CLOCK_TICK_RATE 27000000
 
 #endif /* __ASM_ARCH_TIMEX_H__ */
index 49912b48b1b0f7a26c2b65729686687f84bb460a..a1c0b6b99edf03e1fa4ad6847797995a8a349d0f 100644 (file)
@@ -24,7 +24,7 @@ void __iomem *davinci_ioremap(unsigned long p, size_t size, unsigned int type)
        if (BETWEEN(p, IO_PHYS, IO_SIZE))
                return XLATE(p, IO_PHYS, IO_VIRT);
 
-       return __arm_ioremap(p, size, type);
+       return __arm_ioremap_caller(p, size, type, __builtin_return_address(0));
 }
 EXPORT_SYMBOL(davinci_ioremap);
 
diff --git a/arch/arm/mach-davinci/pm.c b/arch/arm/mach-davinci/pm.c
new file mode 100644 (file)
index 0000000..fab953b
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * DaVinci Power Management Routines
+ *
+ * Copyright (C) 2009 Texas Instruments, Inc. 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/pm.h>
+#include <linux/suspend.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/spinlock.h>
+
+#include <asm/cacheflush.h>
+#include <asm/delay.h>
+
+#include <mach/da8xx.h>
+#include <mach/sram.h>
+#include <mach/pm.h>
+
+#include "clock.h"
+
+#define DEEPSLEEP_SLEEPCOUNT_MASK      0xFFFF
+
+static void (*davinci_sram_suspend) (struct davinci_pm_config *);
+static struct davinci_pm_config *pdata;
+
+static void davinci_sram_push(void *dest, void *src, unsigned int size)
+{
+       memcpy(dest, src, size);
+       flush_icache_range((unsigned long)dest, (unsigned long)(dest + size));
+}
+
+static void davinci_pm_suspend(void)
+{
+       unsigned val;
+
+       if (pdata->cpupll_reg_base != pdata->ddrpll_reg_base) {
+
+               /* Switch CPU PLL to bypass mode */
+               val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
+               val &= ~(PLLCTL_PLLENSRC | PLLCTL_PLLEN);
+               __raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
+
+               udelay(PLL_BYPASS_TIME);
+
+               /* Powerdown CPU PLL */
+               val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
+               val |= PLLCTL_PLLPWRDN;
+               __raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
+       }
+
+       /* Configure sleep count in deep sleep register */
+       val = __raw_readl(pdata->deepsleep_reg);
+       val &= ~DEEPSLEEP_SLEEPCOUNT_MASK,
+       val |= pdata->sleepcount;
+       __raw_writel(val, pdata->deepsleep_reg);
+
+       /* System goes to sleep in this call */
+       davinci_sram_suspend(pdata);
+
+       if (pdata->cpupll_reg_base != pdata->ddrpll_reg_base) {
+
+               /* put CPU PLL in reset */
+               val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
+               val &= ~PLLCTL_PLLRST;
+               __raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
+
+               /* put CPU PLL in power down */
+               val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
+               val &= ~PLLCTL_PLLPWRDN;
+               __raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
+
+               /* wait for CPU PLL reset */
+               udelay(PLL_RESET_TIME);
+
+               /* bring CPU PLL out of reset */
+               val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
+               val |= PLLCTL_PLLRST;
+               __raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
+
+               /* Wait for CPU PLL to lock */
+               udelay(PLL_LOCK_TIME);
+
+               /* Remove CPU PLL from bypass mode */
+               val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
+               val &= ~PLLCTL_PLLENSRC;
+               val |= PLLCTL_PLLEN;
+               __raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
+       }
+}
+
+static int davinci_pm_enter(suspend_state_t state)
+{
+       int ret = 0;
+
+       switch (state) {
+       case PM_SUSPEND_STANDBY:
+       case PM_SUSPEND_MEM:
+               davinci_pm_suspend();
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static struct platform_suspend_ops davinci_pm_ops = {
+       .enter          = davinci_pm_enter,
+       .valid          = suspend_valid_only_mem,
+};
+
+static int __init davinci_pm_probe(struct platform_device *pdev)
+{
+       pdata = pdev->dev.platform_data;
+       if (!pdata) {
+               dev_err(&pdev->dev, "cannot get platform data\n");
+               return -ENOENT;
+       }
+
+       davinci_sram_suspend = sram_alloc(davinci_cpu_suspend_sz, NULL);
+       if (!davinci_sram_suspend) {
+               dev_err(&pdev->dev, "cannot allocate SRAM memory\n");
+               return -ENOMEM;
+       }
+
+       davinci_sram_push(davinci_sram_suspend, davinci_cpu_suspend,
+                                               davinci_cpu_suspend_sz);
+
+       suspend_set_ops(&davinci_pm_ops);
+
+       return 0;
+}
+
+static int __exit davinci_pm_remove(struct platform_device *pdev)
+{
+       sram_free(davinci_sram_suspend, davinci_cpu_suspend_sz);
+       return 0;
+}
+
+static struct platform_driver davinci_pm_driver = {
+       .driver = {
+               .name    = "pm-davinci",
+               .owner   = THIS_MODULE,
+       },
+       .remove = __exit_p(davinci_pm_remove),
+};
+
+static int __init davinci_pm_init(void)
+{
+       return platform_driver_probe(&davinci_pm_driver, davinci_pm_probe);
+}
+late_initcall(davinci_pm_init);
index 04a3cb72c5ab61bdac482a3c404c9c51a5a7a7b3..adf6b5c7f1e55157fb5d0c2fce32e34ce637b655 100644 (file)
 #include <mach/cputype.h>
 #include <mach/psc.h>
 
-/* PSC register offsets */
-#define EPCPR          0x070
-#define PTCMD          0x120
-#define PTSTAT         0x128
-#define PDSTAT         0x200
-#define PDCTL1         0x304
-#define MDSTAT         0x800
-#define MDCTL          0xA00
-
-#define MDSTAT_STATE_MASK 0x1f
-
 /* Return nonzero iff the domain's clock is active */
 int __init davinci_psc_is_clk_active(unsigned int ctlr, unsigned int id)
 {
diff --git a/arch/arm/mach-davinci/sleep.S b/arch/arm/mach-davinci/sleep.S
new file mode 100644 (file)
index 0000000..fb5e72b
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * (C) Copyright 2009, Texas Instruments, Inc. 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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
+ */
+
+/* replicated define because linux/bitops.h cannot be included in assembly */
+#define BIT(nr)                        (1 << (nr))
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <mach/psc.h>
+#include <mach/memory.h>
+
+#include "clock.h"
+
+/* Arbitrary, hardware currently does not update PHYRDY correctly */
+#define PHYRDY_CYCLES          0x1000
+
+/* Assume 25 MHz speed for the cycle conversions since PLLs are bypassed */
+#define PLL_BYPASS_CYCLES      (PLL_BYPASS_TIME * 25)
+#define PLL_RESET_CYCLES       (PLL_RESET_TIME * 25)
+#define PLL_LOCK_CYCLES                (PLL_LOCK_TIME * 25)
+
+#define DEEPSLEEP_SLEEPENABLE_BIT      BIT(31)
+
+       .text
+/*
+ * Move DaVinci into deep sleep state
+ *
+ * Note: This code is copied to internal SRAM by PM code. When the DaVinci
+ *      wakes up it continues execution at the point it went to sleep.
+ * Register Usage:
+ *     r0: contains virtual base for DDR2 controller
+ *     r1: contains virtual base for DDR2 Power and Sleep controller (PSC)
+ *     r2: contains PSC number for DDR2
+ *     r3: contains virtual base DDR2 PLL controller
+ *     r4: contains virtual address of the DEEPSLEEP register
+ */
+ENTRY(davinci_cpu_suspend)
+       stmfd   sp!, {r0-r12, lr}               @ save registers on stack
+
+       ldr     ip, CACHE_FLUSH
+       blx     ip
+
+       ldmia   r0, {r0-r4}
+
+       /*
+        * Switch DDR to self-refresh mode.
+        */
+
+       /* calculate SDRCR address */
+       ldr     ip, [r0, #DDR2_SDRCR_OFFSET]
+       bic     ip, ip, #DDR2_SRPD_BIT
+       orr     ip, ip, #DDR2_LPMODEN_BIT
+       str     ip, [r0, #DDR2_SDRCR_OFFSET]
+
+       ldr     ip, [r0, #DDR2_SDRCR_OFFSET]
+       orr     ip, ip, #DDR2_MCLKSTOPEN_BIT
+       str     ip, [r0, #DDR2_SDRCR_OFFSET]
+
+       mov     ip, #PHYRDY_CYCLES
+1:     subs    ip, ip, #0x1
+       bne     1b
+
+       /* Disable DDR2 LPSC */
+       mov     r7, r0
+       mov     r0, #0x2
+       bl davinci_ddr_psc_config
+       mov     r0, r7
+
+       /* Disable clock to DDR PHY */
+       ldr     ip, [r3, #PLLDIV1]
+       bic     ip, ip, #PLLDIV_EN
+       str     ip, [r3, #PLLDIV1]
+
+       /* Put the DDR PLL in bypass and power down */
+       ldr     ip, [r3, #PLLCTL]
+       bic     ip, ip, #PLLCTL_PLLENSRC
+       bic     ip, ip, #PLLCTL_PLLEN
+       str     ip, [r3, #PLLCTL]
+
+       /* Wait for PLL to switch to bypass */
+       mov     ip, #PLL_BYPASS_CYCLES
+2:     subs    ip, ip, #0x1
+       bne     2b
+
+       /* Power down the PLL */
+       ldr     ip, [r3, #PLLCTL]
+       orr     ip, ip, #PLLCTL_PLLPWRDN
+       str     ip, [r3, #PLLCTL]
+
+       /* Go to deep sleep */
+       ldr     ip, [r4]
+       orr     ip, ip, #DEEPSLEEP_SLEEPENABLE_BIT
+       /* System goes to sleep beyond after this instruction */
+       str     ip, [r4]
+
+       /* Wake up from sleep */
+
+       /* Clear sleep enable */
+       ldr     ip, [r4]
+       bic     ip, ip, #DEEPSLEEP_SLEEPENABLE_BIT
+       str     ip, [r4]
+
+       /* initialize the DDR PLL controller */
+
+       /* Put PLL in reset */
+       ldr     ip, [r3, #PLLCTL]
+       bic     ip, ip, #PLLCTL_PLLRST
+       str     ip, [r3, #PLLCTL]
+
+       /* Clear PLL power down */
+       ldr     ip, [r3, #PLLCTL]
+       bic     ip, ip, #PLLCTL_PLLPWRDN
+       str     ip, [r3, #PLLCTL]
+
+       mov     ip, #PLL_RESET_CYCLES
+3:     subs    ip, ip, #0x1
+       bne     3b
+
+       /* Bring PLL out of reset */
+       ldr     ip, [r3, #PLLCTL]
+       orr     ip, ip, #PLLCTL_PLLRST
+       str     ip, [r3, #PLLCTL]
+
+       /* Wait for PLL to lock (assume prediv = 1, 25MHz OSCIN) */
+       mov     ip, #PLL_LOCK_CYCLES
+4:     subs    ip, ip, #0x1
+       bne     4b
+
+       /* Remove PLL from bypass mode */
+       ldr     ip, [r3, #PLLCTL]
+       bic     ip, ip, #PLLCTL_PLLENSRC
+       orr     ip, ip, #PLLCTL_PLLEN
+       str     ip, [r3, #PLLCTL]
+
+       /* Start 2x clock to DDR2 */
+
+       ldr     ip, [r3, #PLLDIV1]
+       orr     ip, ip, #PLLDIV_EN
+       str     ip, [r3, #PLLDIV1]
+
+       /* Enable VCLK */
+
+       /* Enable DDR2 LPSC */
+       mov     r7, r0
+       mov     r0, #0x3
+       bl davinci_ddr_psc_config
+       mov     r0, r7
+
+       /* clear  MCLKSTOPEN */
+
+       ldr     ip, [r0, #DDR2_SDRCR_OFFSET]
+       bic     ip, ip, #DDR2_MCLKSTOPEN_BIT
+       str     ip, [r0, #DDR2_SDRCR_OFFSET]
+
+       ldr     ip, [r0, #DDR2_SDRCR_OFFSET]
+       bic     ip, ip, #DDR2_LPMODEN_BIT
+       str     ip, [r0, #DDR2_SDRCR_OFFSET]
+
+       /* Restore registers and return */
+       ldmfd   sp!, {r0-r12, pc}
+
+ENDPROC(davinci_cpu_suspend)
+
+/*
+ * Disables or Enables DDR2 LPSC
+ * Register Usage:
+ *     r0: Enable or Disable LPSC r0 = 0x3 => Enable, r0 = 0x2 => Disable LPSC
+ *     r1: contains virtual base for DDR2 Power and Sleep controller (PSC)
+ *     r2: contains PSC number for DDR2
+ */
+ENTRY(davinci_ddr_psc_config)
+       /* Set next state in mdctl for DDR2 */
+       mov     r6, #MDCTL
+       add     r6, r6, r2, lsl #2
+       ldr     ip, [r1, r6]
+       bic     ip, ip, #MDSTAT_STATE_MASK
+       orr     ip, ip, r0
+       str     ip, [r1, r6]
+
+       /* Enable the Power Domain Transition Command */
+       ldr     ip, [r1, #PTCMD]
+       orr     ip, ip, #0x1
+       str     ip, [r1, #PTCMD]
+
+       /* Check for Transition Complete (PTSTAT) */
+ptstat_done:
+       ldr     ip, [r1, #PTSTAT]
+       and     ip, ip, #0x1
+       cmp     ip, #0x0
+       bne     ptstat_done
+
+       /* Check for DDR2 clock disable completion; */
+       mov     r6, #MDSTAT
+       add     r6, r6, r2, lsl #2
+ddr2clk_stop_done:
+       ldr     ip, [r1, r6]
+       and     ip, ip, #MDSTAT_STATE_MASK
+       cmp     ip, r0
+       bne     ddr2clk_stop_done
+
+       mov     pc, lr
+ENDPROC(davinci_ddr_psc_config)
+
+CACHE_FLUSH:
+       .word   arm926_flush_kern_cache_all
+
+ENTRY(davinci_cpu_suspend_sz)
+       .word   . - davinci_cpu_suspend
+ENDPROC(davinci_cpu_suspend_sz)
index 9b89ec7d3040fe272c1a1c5e7ab9b9b8e889d932..1521d13f1d14928a12a1a8b79ad4fd4d5037e3c1 100644 (file)
@@ -8,7 +8,7 @@
 
 #include <mach/bridge-regs.h>
 
-       .macro  addruart,rx
+       .macro  addruart, rx, tmp
        mrc     p15, 0, \rx, c1, c0
        tst     \rx, #1                                 @ MMU enabled?
        ldreq   \rx, =DOVE_SB_REGS_PHYS_BASE
index 8b2c974755c6d0045cf0ff4ee7fb9d6b05005a41..a28792cf761e1618dbd66bdde8115dd3b3bc60b1 100644 (file)
@@ -2,4 +2,4 @@
  * arch/arm/mach-dove/include/mach/vmalloc.h
  */
 
-#define VMALLOC_END    0xfd800000
+#define VMALLOC_END    0xfd800000UL
index 1dde8227f3a274d33d32f28a4b9d89cf9b56ac9f..ebbd89f0e6c0e8967171396e4113e82c6826d266 100644 (file)
@@ -11,7 +11,7 @@
  *
 **/
 
-               .macro  addruart,rx
+               .macro  addruart, rx, tmp
                mov     \rx, #0xf0000000
                orr     \rx, \rx, #0x00000be0
                .endm
index 9167c3d2a5edaf02ef6b74df0a00cab5572341ba..3a08b18f6433e28a35d3e2b4568bc6758c502082 100644 (file)
@@ -161,6 +161,20 @@ config MACH_MICRO9S
          Say 'Y' here if you want your kernel to support the
          Contec Micro9-Slim board.
 
+config MACH_SIM_ONE
+        bool "Support Simplemachines Sim.One board"
+        depends on EP93XX_SDCE0_PHYS_OFFSET
+        help
+          Say 'Y' here if you want your kernel to support the
+          Simplemachines Sim.One board.
+
+config MACH_SNAPPER_CL15
+       bool "Support Bluewater Systems Snapper CL15 Module"
+       depends on EP93XX_SDCE0_PHYS_OFFSET
+       help
+         Say 'Y' here if you want your kernel to support the Bluewater
+         Systems Snapper CL15 Module.
+
 config MACH_TS72XX
        bool "Support Technologic Systems TS-72xx SBC"
        depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET
index eae6199a9891af49845774d9ddfc5f9b9e903007..33ee2c863d1808a1015098975fed81fe238e30d7 100644 (file)
@@ -10,4 +10,6 @@ obj-$(CONFIG_MACH_ADSSPHERE)  += adssphere.o
 obj-$(CONFIG_MACH_EDB93XX)     += edb93xx.o
 obj-$(CONFIG_MACH_GESBC9312)   += gesbc9312.o
 obj-$(CONFIG_MACH_MICRO9)      += micro9.o
+obj-$(CONFIG_MACH_SIM_ONE)     += simone.o
+obj-$(CONFIG_MACH_SNAPPER_CL15)        += snappercl15.o
 obj-$(CONFIG_MACH_TS72XX)      += ts72xx.o
index 1d0f9d8aff2e93583ba5ff0793f80d0f991f4786..5f80092b6ace0ec1c9c6b0fea7c334a83029e67a 100644 (file)
@@ -10,6 +10,8 @@
  * your option) any later version.
  */
 
+#define pr_fmt(fmt) "ep93xx " KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/clk.h>
 #include <linux/err.h>
@@ -445,37 +447,39 @@ static void __init ep93xx_dma_clock_init(void)
 static int __init ep93xx_clock_init(void)
 {
        u32 value;
-       int i;
 
-       value = __raw_readl(EP93XX_SYSCON_CLOCK_SET1);
-       if (!(value & 0x00800000)) {                    /* PLL1 bypassed?  */
+       /* Determine the bootloader configured pll1 rate */
+       value = __raw_readl(EP93XX_SYSCON_CLKSET1);
+       if (!(value & EP93XX_SYSCON_CLKSET1_NBYP1))
                clk_pll1.rate = clk_xtali.rate;
-       } else {
+       else
                clk_pll1.rate = calc_pll_rate(value);
-       }
+
+       /* Initialize the pll1 derived clocks */
        clk_f.rate = clk_pll1.rate / fclk_divisors[(value >> 25) & 0x7];
        clk_h.rate = clk_pll1.rate / hclk_divisors[(value >> 20) & 0x7];
        clk_p.rate = clk_h.rate / pclk_divisors[(value >> 18) & 0x3];
        ep93xx_dma_clock_init();
 
-       value = __raw_readl(EP93XX_SYSCON_CLOCK_SET2);
-       if (!(value & 0x00080000)) {                    /* PLL2 bypassed?  */
+       /* Determine the bootloader configured pll2 rate */
+       value = __raw_readl(EP93XX_SYSCON_CLKSET2);
+       if (!(value & EP93XX_SYSCON_CLKSET2_NBYP2))
                clk_pll2.rate = clk_xtali.rate;
-       } else if (value & 0x00040000) {                /* PLL2 enabled?  */
+       else if (value & EP93XX_SYSCON_CLKSET2_PLL2_EN)
                clk_pll2.rate = calc_pll_rate(value);
-       } else {
+       else
                clk_pll2.rate = 0;
-       }
+
+       /* Initialize the pll2 derived clocks */
        clk_usb_host.rate = clk_pll2.rate / (((value >> 28) & 0xf) + 1);
 
-       printk(KERN_INFO "ep93xx: PLL1 running at %ld MHz, PLL2 at %ld MHz\n",
+       pr_info("PLL1 running at %ld MHz, PLL2 at %ld MHz\n",
                clk_pll1.rate / 1000000, clk_pll2.rate / 1000000);
-       printk(KERN_INFO "ep93xx: FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n",
+       pr_info("FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n",
                clk_f.rate / 1000000, clk_h.rate / 1000000,
                clk_p.rate / 1000000);
 
-       for (i = 0; i < ARRAY_SIZE(clocks); i++)
-               clkdev_add(&clocks[i]);
+       clkdev_add_table(clocks, ARRAY_SIZE(clocks));
        return 0;
 }
 arch_initcall(ep93xx_clock_init);
index 1f0d66561bbe158b49fdd9c3e47d3b400e340ecb..90fb591cbffa6066e0b5fb732a0079834471c357 100644 (file)
  * your option) any later version.
  */
 
+#define pr_fmt(fmt) "ep93xx " KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/dma-mapping.h>
 #include <linux/timex.h>
+#include <linux/irq.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
 #include <linux/leds.h>
@@ -35,7 +38,6 @@
 
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
-#include <asm/mach/irq.h>
 
 #include <asm/hardware/vic.h>
 
@@ -82,13 +84,40 @@ void __init ep93xx_map_io(void)
  * to use this timer for something else.  We also use timer 4 for keeping
  * track of lost jiffies.
  */
-static unsigned int last_jiffy_time;
-
+#define EP93XX_TIMER_REG(x)            (EP93XX_TIMER_BASE + (x))
+#define EP93XX_TIMER1_LOAD             EP93XX_TIMER_REG(0x00)
+#define EP93XX_TIMER1_VALUE            EP93XX_TIMER_REG(0x04)
+#define EP93XX_TIMER1_CONTROL          EP93XX_TIMER_REG(0x08)
+#define EP93XX_TIMER123_CONTROL_ENABLE (1 << 7)
+#define EP93XX_TIMER123_CONTROL_MODE   (1 << 6)
+#define EP93XX_TIMER123_CONTROL_CLKSEL (1 << 3)
+#define EP93XX_TIMER1_CLEAR            EP93XX_TIMER_REG(0x0c)
+#define EP93XX_TIMER2_LOAD             EP93XX_TIMER_REG(0x20)
+#define EP93XX_TIMER2_VALUE            EP93XX_TIMER_REG(0x24)
+#define EP93XX_TIMER2_CONTROL          EP93XX_TIMER_REG(0x28)
+#define EP93XX_TIMER2_CLEAR            EP93XX_TIMER_REG(0x2c)
+#define EP93XX_TIMER4_VALUE_LOW                EP93XX_TIMER_REG(0x60)
+#define EP93XX_TIMER4_VALUE_HIGH       EP93XX_TIMER_REG(0x64)
+#define EP93XX_TIMER4_VALUE_HIGH_ENABLE        (1 << 8)
+#define EP93XX_TIMER3_LOAD             EP93XX_TIMER_REG(0x80)
+#define EP93XX_TIMER3_VALUE            EP93XX_TIMER_REG(0x84)
+#define EP93XX_TIMER3_CONTROL          EP93XX_TIMER_REG(0x88)
+#define EP93XX_TIMER3_CLEAR            EP93XX_TIMER_REG(0x8c)
+
+#define EP93XX_TIMER123_CLOCK          508469
+#define EP93XX_TIMER4_CLOCK            983040
+
+#define TIMER1_RELOAD                  ((EP93XX_TIMER123_CLOCK / HZ) - 1)
 #define TIMER4_TICKS_PER_JIFFY         DIV_ROUND_CLOSEST(CLOCK_TICK_RATE, HZ)
 
+static unsigned int last_jiffy_time;
+
 static irqreturn_t ep93xx_timer_interrupt(int irq, void *dev_id)
 {
+       /* Writing any value clears the timer interrupt */
        __raw_writel(1, EP93XX_TIMER1_CLEAR);
+
+       /* Recover lost jiffies */
        while ((signed long)
                (__raw_readl(EP93XX_TIMER4_VALUE_LOW) - last_jiffy_time)
                                                >= TIMER4_TICKS_PER_JIFFY) {
@@ -107,13 +136,18 @@ static struct irqaction ep93xx_timer_irq = {
 
 static void __init ep93xx_timer_init(void)
 {
+       u32 tmode = EP93XX_TIMER123_CONTROL_MODE |
+                   EP93XX_TIMER123_CONTROL_CLKSEL;
+
        /* Enable periodic HZ timer.  */
-       __raw_writel(0x48, EP93XX_TIMER1_CONTROL);
-       __raw_writel((508469 / HZ) - 1, EP93XX_TIMER1_LOAD);
-       __raw_writel(0xc8, EP93XX_TIMER1_CONTROL);
+       __raw_writel(tmode, EP93XX_TIMER1_CONTROL);
+       __raw_writel(TIMER1_RELOAD, EP93XX_TIMER1_LOAD);
+       __raw_writel(tmode | EP93XX_TIMER123_CONTROL_ENABLE,
+                       EP93XX_TIMER1_CONTROL);
 
        /* Enable lost jiffy timer.  */
-       __raw_writel(0x100, EP93XX_TIMER4_VALUE_HIGH);
+       __raw_writel(EP93XX_TIMER4_VALUE_HIGH_ENABLE,
+                       EP93XX_TIMER4_VALUE_HIGH);
 
        setup_irq(IRQ_EP93XX_TIMER1, &ep93xx_timer_irq);
 }
@@ -134,238 +168,17 @@ struct sys_timer ep93xx_timer = {
 };
 
 
-/*************************************************************************
- * GPIO handling for EP93xx
- *************************************************************************/
-static unsigned char gpio_int_unmasked[3];
-static unsigned char gpio_int_enabled[3];
-static unsigned char gpio_int_type1[3];
-static unsigned char gpio_int_type2[3];
-static unsigned char gpio_int_debounce[3];
-
-/* Port ordering is: A B F */
-static const u8 int_type1_register_offset[3]   = { 0x90, 0xac, 0x4c };
-static const u8 int_type2_register_offset[3]   = { 0x94, 0xb0, 0x50 };
-static const u8 eoi_register_offset[3]         = { 0x98, 0xb4, 0x54 };
-static const u8 int_en_register_offset[3]      = { 0x9c, 0xb8, 0x58 };
-static const u8 int_debounce_register_offset[3]        = { 0xa8, 0xc4, 0x64 };
-
-void ep93xx_gpio_update_int_params(unsigned port)
-{
-       BUG_ON(port > 2);
-
-       __raw_writeb(0, EP93XX_GPIO_REG(int_en_register_offset[port]));
-
-       __raw_writeb(gpio_int_type2[port],
-               EP93XX_GPIO_REG(int_type2_register_offset[port]));
-
-       __raw_writeb(gpio_int_type1[port],
-               EP93XX_GPIO_REG(int_type1_register_offset[port]));
-
-       __raw_writeb(gpio_int_unmasked[port] & gpio_int_enabled[port],
-               EP93XX_GPIO_REG(int_en_register_offset[port]));
-}
-
-void ep93xx_gpio_int_mask(unsigned line)
-{
-       gpio_int_unmasked[line >> 3] &= ~(1 << (line & 7));
-}
-
-void ep93xx_gpio_int_debounce(unsigned int irq, int enable)
-{
-       int line = irq_to_gpio(irq);
-       int port = line >> 3;
-       int port_mask = 1 << (line & 7);
-
-       if (enable)
-               gpio_int_debounce[port] |= port_mask;
-       else
-               gpio_int_debounce[port] &= ~port_mask;
-
-       __raw_writeb(gpio_int_debounce[port],
-               EP93XX_GPIO_REG(int_debounce_register_offset[port]));
-}
-EXPORT_SYMBOL(ep93xx_gpio_int_debounce);
-
 /*************************************************************************
  * EP93xx IRQ handling
  *************************************************************************/
-static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc)
-{
-       unsigned char status;
-       int i;
-
-       status = __raw_readb(EP93XX_GPIO_A_INT_STATUS);
-       for (i = 0; i < 8; i++) {
-               if (status & (1 << i)) {
-                       int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_A(0)) + i;
-                       generic_handle_irq(gpio_irq);
-               }
-       }
-
-       status = __raw_readb(EP93XX_GPIO_B_INT_STATUS);
-       for (i = 0; i < 8; i++) {
-               if (status & (1 << i)) {
-                       int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_B(0)) + i;
-                       generic_handle_irq(gpio_irq);
-               }
-       }
-}
-
-static void ep93xx_gpio_f_irq_handler(unsigned int irq, struct irq_desc *desc)
-{
-       /*
-        * map discontiguous hw irq range to continous sw irq range:
-        *
-        *  IRQ_EP93XX_GPIO{0..7}MUX -> gpio_to_irq(EP93XX_GPIO_LINE_F({0..7})
-        */
-       int port_f_idx = ((irq + 1) & 7) ^ 4; /* {19..22,47..50} -> {0..7} */
-       int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_F(0)) + port_f_idx;
-
-       generic_handle_irq(gpio_irq);
-}
-
-static void ep93xx_gpio_irq_ack(unsigned int irq)
-{
-       int line = irq_to_gpio(irq);
-       int port = line >> 3;
-       int port_mask = 1 << (line & 7);
-
-       if ((irq_desc[irq].status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
-               gpio_int_type2[port] ^= port_mask; /* switch edge direction */
-               ep93xx_gpio_update_int_params(port);
-       }
-
-       __raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port]));
-}
-
-static void ep93xx_gpio_irq_mask_ack(unsigned int irq)
-{
-       int line = irq_to_gpio(irq);
-       int port = line >> 3;
-       int port_mask = 1 << (line & 7);
-
-       if ((irq_desc[irq].status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH)
-               gpio_int_type2[port] ^= port_mask; /* switch edge direction */
-
-       gpio_int_unmasked[port] &= ~port_mask;
-       ep93xx_gpio_update_int_params(port);
-
-       __raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port]));
-}
-
-static void ep93xx_gpio_irq_mask(unsigned int irq)
-{
-       int line = irq_to_gpio(irq);
-       int port = line >> 3;
-
-       gpio_int_unmasked[port] &= ~(1 << (line & 7));
-       ep93xx_gpio_update_int_params(port);
-}
-
-static void ep93xx_gpio_irq_unmask(unsigned int irq)
-{
-       int line = irq_to_gpio(irq);
-       int port = line >> 3;
-
-       gpio_int_unmasked[port] |= 1 << (line & 7);
-       ep93xx_gpio_update_int_params(port);
-}
-
-
-/*
- * gpio_int_type1 controls whether the interrupt is level (0) or
- * edge (1) triggered, while gpio_int_type2 controls whether it
- * triggers on low/falling (0) or high/rising (1).
- */
-static int ep93xx_gpio_irq_type(unsigned int irq, unsigned int type)
-{
-       struct irq_desc *desc = irq_desc + irq;
-       const int gpio = irq_to_gpio(irq);
-       const int port = gpio >> 3;
-       const int port_mask = 1 << (gpio & 7);
-
-       gpio_direction_input(gpio);
-
-       switch (type) {
-       case IRQ_TYPE_EDGE_RISING:
-               gpio_int_type1[port] |= port_mask;
-               gpio_int_type2[port] |= port_mask;
-               desc->handle_irq = handle_edge_irq;
-               break;
-       case IRQ_TYPE_EDGE_FALLING:
-               gpio_int_type1[port] |= port_mask;
-               gpio_int_type2[port] &= ~port_mask;
-               desc->handle_irq = handle_edge_irq;
-               break;
-       case IRQ_TYPE_LEVEL_HIGH:
-               gpio_int_type1[port] &= ~port_mask;
-               gpio_int_type2[port] |= port_mask;
-               desc->handle_irq = handle_level_irq;
-               break;
-       case IRQ_TYPE_LEVEL_LOW:
-               gpio_int_type1[port] &= ~port_mask;
-               gpio_int_type2[port] &= ~port_mask;
-               desc->handle_irq = handle_level_irq;
-               break;
-       case IRQ_TYPE_EDGE_BOTH:
-               gpio_int_type1[port] |= port_mask;
-               /* set initial polarity based on current input level */
-               if (gpio_get_value(gpio))
-                       gpio_int_type2[port] &= ~port_mask; /* falling */
-               else
-                       gpio_int_type2[port] |= port_mask; /* rising */
-               desc->handle_irq = handle_edge_irq;
-               break;
-       default:
-               pr_err("ep93xx: failed to set irq type %d for gpio %d\n",
-                      type, gpio);
-               return -EINVAL;
-       }
-
-       gpio_int_enabled[port] |= port_mask;
-
-       desc->status &= ~IRQ_TYPE_SENSE_MASK;
-       desc->status |= type & IRQ_TYPE_SENSE_MASK;
-
-       ep93xx_gpio_update_int_params(port);
-
-       return 0;
-}
-
-static struct irq_chip ep93xx_gpio_irq_chip = {
-       .name           = "GPIO",
-       .ack            = ep93xx_gpio_irq_ack,
-       .mask_ack       = ep93xx_gpio_irq_mask_ack,
-       .mask           = ep93xx_gpio_irq_mask,
-       .unmask         = ep93xx_gpio_irq_unmask,
-       .set_type       = ep93xx_gpio_irq_type,
-};
-
+extern void ep93xx_gpio_init_irq(void);
 
 void __init ep93xx_init_irq(void)
 {
-       int gpio_irq;
-
        vic_init(EP93XX_VIC1_BASE, 0, EP93XX_VIC1_VALID_IRQ_MASK, 0);
        vic_init(EP93XX_VIC2_BASE, 32, EP93XX_VIC2_VALID_IRQ_MASK, 0);
 
-       for (gpio_irq = gpio_to_irq(0);
-            gpio_irq <= gpio_to_irq(EP93XX_GPIO_LINE_MAX_IRQ); ++gpio_irq) {
-               set_irq_chip(gpio_irq, &ep93xx_gpio_irq_chip);
-               set_irq_handler(gpio_irq, handle_level_irq);
-               set_irq_flags(gpio_irq, IRQF_VALID);
-       }
-
-       set_irq_chained_handler(IRQ_EP93XX_GPIO_AB, ep93xx_gpio_ab_irq_handler);
-       set_irq_chained_handler(IRQ_EP93XX_GPIO0MUX, ep93xx_gpio_f_irq_handler);
-       set_irq_chained_handler(IRQ_EP93XX_GPIO1MUX, ep93xx_gpio_f_irq_handler);
-       set_irq_chained_handler(IRQ_EP93XX_GPIO2MUX, ep93xx_gpio_f_irq_handler);
-       set_irq_chained_handler(IRQ_EP93XX_GPIO3MUX, ep93xx_gpio_f_irq_handler);
-       set_irq_chained_handler(IRQ_EP93XX_GPIO4MUX, ep93xx_gpio_f_irq_handler);
-       set_irq_chained_handler(IRQ_EP93XX_GPIO5MUX, ep93xx_gpio_f_irq_handler);
-       set_irq_chained_handler(IRQ_EP93XX_GPIO6MUX, ep93xx_gpio_f_irq_handler);
-       set_irq_chained_handler(IRQ_EP93XX_GPIO7MUX, ep93xx_gpio_f_irq_handler);
+       ep93xx_gpio_init_irq();
 }
 
 
@@ -572,9 +385,9 @@ void __init ep93xx_register_i2c(struct i2c_gpio_platform_data *data,
         * CMOS driver.
         */
        if (data->sda_is_open_drain && data->sda_pin != EP93XX_GPIO_LINE_EEDAT)
-               pr_warning("ep93xx: sda != EEDAT, open drain has no effect\n");
+               pr_warning("sda != EEDAT, open drain has no effect\n");
        if (data->scl_is_open_drain && data->scl_pin != EP93XX_GPIO_LINE_EECLK)
-               pr_warning("ep93xx: scl != EECLK, open drain has no effect\n");
+               pr_warning("scl != EECLK, open drain has no effect\n");
 
        __raw_writel((data->sda_is_open_drain << 1) |
                     (data->scl_is_open_drain << 0),
index dbcac9c40a28883df558565be3c7e52c37426053..8904ca4e2e24fc9a4984bd0b88ce9d3eab52e7ea 100644 (file)
@@ -28,6 +28,8 @@
  * with this implementation.
  */
 
+#define pr_fmt(fmt) "ep93xx " KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/clk.h>
 #include <linux/err.h>
@@ -173,7 +175,7 @@ static irqreturn_t m2p_irq(int irq, void *dev_id)
 
        switch (m2p_channel_state(ch)) {
        case STATE_IDLE:
-               pr_crit("m2p_irq: dma interrupt without a dma buffer\n");
+               pr_crit("dma interrupt without a dma buffer\n");
                BUG();
                break;
 
@@ -197,7 +199,7 @@ static irqreturn_t m2p_irq(int irq, void *dev_id)
                break;
 
        case STATE_NEXT:
-               pr_crit("m2p_irq: dma interrupt while next\n");
+               pr_crit("dma interrupt while next\n");
                BUG();
                break;
        }
index a4a7be3080002cb2c1577eeb2cb1cfb40ec4b68c..d22d67ac8b9938cd444fa6d212cf0acdaa8beba8 100644 (file)
@@ -118,12 +118,33 @@ static void __init edb93xx_register_i2c(void)
        }
 }
 
+
+/*************************************************************************
+ * EDB93xx pwm
+ *************************************************************************/
+static void __init edb93xx_register_pwm(void)
+{
+       if (machine_is_edb9301() ||
+           machine_is_edb9302() || machine_is_edb9302a()) {
+               /* EP9301 and EP9302 only have pwm.1 (EGPIO14) */
+               ep93xx_register_pwm(0, 1);
+       } else if (machine_is_edb9307() || machine_is_edb9307a()) {
+               /* EP9307 only has pwm.0 (PWMOUT) */
+               ep93xx_register_pwm(1, 0);
+       } else {
+               /* EP9312 and EP9315 have both */
+               ep93xx_register_pwm(1, 1);
+       }
+}
+
+
 static void __init edb93xx_init_machine(void)
 {
        ep93xx_init_devices();
        edb93xx_register_flash();
        ep93xx_register_eth(&edb93xx_eth_data, 1);
        edb93xx_register_i2c();
+       edb93xx_register_pwm();
 }
 
 
index 1ea8871e03a96db862ef27ebca06fc325baeb6aa..cc377ae8c4281324926f6d8f9c6ac645cd53b487 100644 (file)
@@ -13,6 +13,8 @@
  *  published by the Free Software Foundation.
  */
 
+#define pr_fmt(fmt) "ep93xx " KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/seq_file.h>
 
 #include <mach/hardware.h>
 
+/*************************************************************************
+ * GPIO handling for EP93xx
+ *************************************************************************/
+static unsigned char gpio_int_unmasked[3];
+static unsigned char gpio_int_enabled[3];
+static unsigned char gpio_int_type1[3];
+static unsigned char gpio_int_type2[3];
+static unsigned char gpio_int_debounce[3];
+
+/* Port ordering is: A B F */
+static const u8 int_type1_register_offset[3]   = { 0x90, 0xac, 0x4c };
+static const u8 int_type2_register_offset[3]   = { 0x94, 0xb0, 0x50 };
+static const u8 eoi_register_offset[3]         = { 0x98, 0xb4, 0x54 };
+static const u8 int_en_register_offset[3]      = { 0x9c, 0xb8, 0x58 };
+static const u8 int_debounce_register_offset[3]        = { 0xa8, 0xc4, 0x64 };
+
+void ep93xx_gpio_update_int_params(unsigned port)
+{
+       BUG_ON(port > 2);
+
+       __raw_writeb(0, EP93XX_GPIO_REG(int_en_register_offset[port]));
+
+       __raw_writeb(gpio_int_type2[port],
+               EP93XX_GPIO_REG(int_type2_register_offset[port]));
+
+       __raw_writeb(gpio_int_type1[port],
+               EP93XX_GPIO_REG(int_type1_register_offset[port]));
+
+       __raw_writeb(gpio_int_unmasked[port] & gpio_int_enabled[port],
+               EP93XX_GPIO_REG(int_en_register_offset[port]));
+}
+
+void ep93xx_gpio_int_mask(unsigned line)
+{
+       gpio_int_unmasked[line >> 3] &= ~(1 << (line & 7));
+}
+
+void ep93xx_gpio_int_debounce(unsigned int irq, int enable)
+{
+       int line = irq_to_gpio(irq);
+       int port = line >> 3;
+       int port_mask = 1 << (line & 7);
+
+       if (enable)
+               gpio_int_debounce[port] |= port_mask;
+       else
+               gpio_int_debounce[port] &= ~port_mask;
+
+       __raw_writeb(gpio_int_debounce[port],
+               EP93XX_GPIO_REG(int_debounce_register_offset[port]));
+}
+EXPORT_SYMBOL(ep93xx_gpio_int_debounce);
+
+static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+       unsigned char status;
+       int i;
+
+       status = __raw_readb(EP93XX_GPIO_A_INT_STATUS);
+       for (i = 0; i < 8; i++) {
+               if (status & (1 << i)) {
+                       int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_A(0)) + i;
+                       generic_handle_irq(gpio_irq);
+               }
+       }
+
+       status = __raw_readb(EP93XX_GPIO_B_INT_STATUS);
+       for (i = 0; i < 8; i++) {
+               if (status & (1 << i)) {
+                       int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_B(0)) + i;
+                       generic_handle_irq(gpio_irq);
+               }
+       }
+}
+
+static void ep93xx_gpio_f_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+       /*
+        * map discontiguous hw irq range to continous sw irq range:
+        *
+        *  IRQ_EP93XX_GPIO{0..7}MUX -> gpio_to_irq(EP93XX_GPIO_LINE_F({0..7})
+        */
+       int port_f_idx = ((irq + 1) & 7) ^ 4; /* {19..22,47..50} -> {0..7} */
+       int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_F(0)) + port_f_idx;
+
+       generic_handle_irq(gpio_irq);
+}
+
+static void ep93xx_gpio_irq_ack(unsigned int irq)
+{
+       int line = irq_to_gpio(irq);
+       int port = line >> 3;
+       int port_mask = 1 << (line & 7);
+
+       if ((irq_desc[irq].status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
+               gpio_int_type2[port] ^= port_mask; /* switch edge direction */
+               ep93xx_gpio_update_int_params(port);
+       }
+
+       __raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port]));
+}
+
+static void ep93xx_gpio_irq_mask_ack(unsigned int irq)
+{
+       int line = irq_to_gpio(irq);
+       int port = line >> 3;
+       int port_mask = 1 << (line & 7);
+
+       if ((irq_desc[irq].status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH)
+               gpio_int_type2[port] ^= port_mask; /* switch edge direction */
+
+       gpio_int_unmasked[port] &= ~port_mask;
+       ep93xx_gpio_update_int_params(port);
+
+       __raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port]));
+}
+
+static void ep93xx_gpio_irq_mask(unsigned int irq)
+{
+       int line = irq_to_gpio(irq);
+       int port = line >> 3;
+
+       gpio_int_unmasked[port] &= ~(1 << (line & 7));
+       ep93xx_gpio_update_int_params(port);
+}
+
+static void ep93xx_gpio_irq_unmask(unsigned int irq)
+{
+       int line = irq_to_gpio(irq);
+       int port = line >> 3;
+
+       gpio_int_unmasked[port] |= 1 << (line & 7);
+       ep93xx_gpio_update_int_params(port);
+}
+
+/*
+ * gpio_int_type1 controls whether the interrupt is level (0) or
+ * edge (1) triggered, while gpio_int_type2 controls whether it
+ * triggers on low/falling (0) or high/rising (1).
+ */
+static int ep93xx_gpio_irq_type(unsigned int irq, unsigned int type)
+{
+       struct irq_desc *desc = irq_desc + irq;
+       const int gpio = irq_to_gpio(irq);
+       const int port = gpio >> 3;
+       const int port_mask = 1 << (gpio & 7);
+
+       gpio_direction_input(gpio);
+
+       switch (type) {
+       case IRQ_TYPE_EDGE_RISING:
+               gpio_int_type1[port] |= port_mask;
+               gpio_int_type2[port] |= port_mask;
+               desc->handle_irq = handle_edge_irq;
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               gpio_int_type1[port] |= port_mask;
+               gpio_int_type2[port] &= ~port_mask;
+               desc->handle_irq = handle_edge_irq;
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               gpio_int_type1[port] &= ~port_mask;
+               gpio_int_type2[port] |= port_mask;
+               desc->handle_irq = handle_level_irq;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               gpio_int_type1[port] &= ~port_mask;
+               gpio_int_type2[port] &= ~port_mask;
+               desc->handle_irq = handle_level_irq;
+               break;
+       case IRQ_TYPE_EDGE_BOTH:
+               gpio_int_type1[port] |= port_mask;
+               /* set initial polarity based on current input level */
+               if (gpio_get_value(gpio))
+                       gpio_int_type2[port] &= ~port_mask; /* falling */
+               else
+                       gpio_int_type2[port] |= port_mask; /* rising */
+               desc->handle_irq = handle_edge_irq;
+               break;
+       default:
+               pr_err("failed to set irq type %d for gpio %d\n", type, gpio);
+               return -EINVAL;
+       }
+
+       gpio_int_enabled[port] |= port_mask;
+
+       desc->status &= ~IRQ_TYPE_SENSE_MASK;
+       desc->status |= type & IRQ_TYPE_SENSE_MASK;
+
+       ep93xx_gpio_update_int_params(port);
+
+       return 0;
+}
+
+static struct irq_chip ep93xx_gpio_irq_chip = {
+       .name           = "GPIO",
+       .ack            = ep93xx_gpio_irq_ack,
+       .mask_ack       = ep93xx_gpio_irq_mask_ack,
+       .mask           = ep93xx_gpio_irq_mask,
+       .unmask         = ep93xx_gpio_irq_unmask,
+       .set_type       = ep93xx_gpio_irq_type,
+};
+
+void __init ep93xx_gpio_init_irq(void)
+{
+       int gpio_irq;
+
+       for (gpio_irq = gpio_to_irq(0);
+            gpio_irq <= gpio_to_irq(EP93XX_GPIO_LINE_MAX_IRQ); ++gpio_irq) {
+               set_irq_chip(gpio_irq, &ep93xx_gpio_irq_chip);
+               set_irq_handler(gpio_irq, handle_level_irq);
+               set_irq_flags(gpio_irq, IRQF_VALID);
+       }
+
+       set_irq_chained_handler(IRQ_EP93XX_GPIO_AB, ep93xx_gpio_ab_irq_handler);
+       set_irq_chained_handler(IRQ_EP93XX_GPIO0MUX, ep93xx_gpio_f_irq_handler);
+       set_irq_chained_handler(IRQ_EP93XX_GPIO1MUX, ep93xx_gpio_f_irq_handler);
+       set_irq_chained_handler(IRQ_EP93XX_GPIO2MUX, ep93xx_gpio_f_irq_handler);
+       set_irq_chained_handler(IRQ_EP93XX_GPIO3MUX, ep93xx_gpio_f_irq_handler);
+       set_irq_chained_handler(IRQ_EP93XX_GPIO4MUX, ep93xx_gpio_f_irq_handler);
+       set_irq_chained_handler(IRQ_EP93XX_GPIO5MUX, ep93xx_gpio_f_irq_handler);
+       set_irq_chained_handler(IRQ_EP93XX_GPIO6MUX, ep93xx_gpio_f_irq_handler);
+       set_irq_chained_handler(IRQ_EP93XX_GPIO7MUX, ep93xx_gpio_f_irq_handler);
+}
+
+
+/*************************************************************************
+ * gpiolib interface for EP93xx on-chip GPIOs
+ *************************************************************************/
 struct ep93xx_gpio_chip {
        struct gpio_chip        chip;
 
@@ -31,10 +262,6 @@ struct ep93xx_gpio_chip {
 
 #define to_ep93xx_gpio_chip(c) container_of(c, struct ep93xx_gpio_chip, chip)
 
-/* From core.c */
-extern void ep93xx_gpio_int_mask(unsigned line);
-extern void ep93xx_gpio_update_int_params(unsigned port);
-
 static int ep93xx_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
        struct ep93xx_gpio_chip *ep93xx_chip = to_ep93xx_gpio_chip(chip);
index 802858bc80958b90358aec6ac399d509efe73193..5cd22444e2236ae8fb73e59641e8dd82347f0fdf 100644 (file)
@@ -11,7 +11,7 @@
  */
 #include <mach/ep93xx-regs.h>
 
-               .macro  addruart,rx
+               .macro  addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                         @ MMU enabled?
                ldreq   \rx, =EP93XX_APB_PHYS_BASE      @ Physical base
index d55194a4c0934391cb096027969a08791e37cadf..93e2ecc79ceb14896e2665acc97a15eac0fd162d 100644 (file)
 
 /* APB peripherals */
 #define EP93XX_TIMER_BASE              EP93XX_APB_IOMEM(0x00010000)
-#define EP93XX_TIMER_REG(x)            (EP93XX_TIMER_BASE + (x))
-#define EP93XX_TIMER1_LOAD             EP93XX_TIMER_REG(0x00)
-#define EP93XX_TIMER1_VALUE            EP93XX_TIMER_REG(0x04)
-#define EP93XX_TIMER1_CONTROL          EP93XX_TIMER_REG(0x08)
-#define EP93XX_TIMER1_CLEAR            EP93XX_TIMER_REG(0x0c)
-#define EP93XX_TIMER2_LOAD             EP93XX_TIMER_REG(0x20)
-#define EP93XX_TIMER2_VALUE            EP93XX_TIMER_REG(0x24)
-#define EP93XX_TIMER2_CONTROL          EP93XX_TIMER_REG(0x28)
-#define EP93XX_TIMER2_CLEAR            EP93XX_TIMER_REG(0x2c)
-#define EP93XX_TIMER4_VALUE_LOW                EP93XX_TIMER_REG(0x60)
-#define EP93XX_TIMER4_VALUE_HIGH       EP93XX_TIMER_REG(0x64)
-#define EP93XX_TIMER3_LOAD             EP93XX_TIMER_REG(0x80)
-#define EP93XX_TIMER3_VALUE            EP93XX_TIMER_REG(0x84)
-#define EP93XX_TIMER3_CONTROL          EP93XX_TIMER_REG(0x88)
-#define EP93XX_TIMER3_CLEAR            EP93XX_TIMER_REG(0x8c)
 
 #define EP93XX_I2S_BASE                        EP93XX_APB_IOMEM(0x00020000)
 
 #define EP93XX_SYSCON_PWRCNT_DMA_M2P1  (1<<16)
 #define EP93XX_SYSCON_HALT             EP93XX_SYSCON_REG(0x08)
 #define EP93XX_SYSCON_STANDBY          EP93XX_SYSCON_REG(0x0c)
-#define EP93XX_SYSCON_CLOCK_SET1       EP93XX_SYSCON_REG(0x20)
-#define EP93XX_SYSCON_CLOCK_SET2       EP93XX_SYSCON_REG(0x24)
+#define EP93XX_SYSCON_CLKSET1          EP93XX_SYSCON_REG(0x20)
+#define EP93XX_SYSCON_CLKSET1_NBYP1    (1<<23)
+#define EP93XX_SYSCON_CLKSET2          EP93XX_SYSCON_REG(0x24)
+#define EP93XX_SYSCON_CLKSET2_NBYP2    (1<<19)
+#define EP93XX_SYSCON_CLKSET2_PLL2_EN  (1<<18)
 #define EP93XX_SYSCON_DEVCFG           EP93XX_SYSCON_REG(0x80)
 #define EP93XX_SYSCON_DEVCFG_SWRST     (1<<31)
 #define EP93XX_SYSCON_DEVCFG_D1ONG     (1<<30)
index 62d17421e48c0f62a4327b9e0a977f781cd71b10..1e2f4e97f428d072b942a5020ab32f28028d084b 100644 (file)
@@ -5,6 +5,8 @@
 #ifndef __ASM_ARCH_EP93XX_KEYPAD_H
 #define __ASM_ARCH_EP93XX_KEYPAD_H
 
+struct matrix_keymap_data;
+
 /* flags for the ep93xx_keypad driver */
 #define EP93XX_KEYPAD_DISABLE_3_KEY    (1<<0)  /* disable 3-key reset */
 #define EP93XX_KEYPAD_DIAG_MODE                (1<<1)  /* diagnostic mode */
 
 /**
  * struct ep93xx_keypad_platform_data - platform specific device structure
- * @matrix_key_map:            array of keycodes defining the keypad matrix
- * @matrix_key_map_size:       ARRAY_SIZE(matrix_key_map)
- * @debounce:                  debounce start count; terminal count is 0xff
- * @prescale:                  row/column counter pre-scaler load value
- * @flags:                     see above
+ * @keymap_data:       pointer to &matrix_keymap_data
+ * @debounce:          debounce start count; terminal count is 0xff
+ * @prescale:          row/column counter pre-scaler load value
+ * @flags:             see above
  */
 struct ep93xx_keypad_platform_data {
-       unsigned int    *matrix_key_map;
-       int             matrix_key_map_size;
+       struct matrix_keymap_data *keymap_data;
        unsigned int    debounce;
        unsigned int    prescale;
        unsigned int    flags;
index aed21cd3fe2d85ba006fe10970cced78a72ba7c9..1b3f25d03d39134d69a6043f257dcc300c04373b 100644 (file)
@@ -2,4 +2,4 @@
  * arch/arm/mach-ep93xx/include/mach/vmalloc.h
  */
 
-#define VMALLOC_END    0xfe800000
+#define VMALLOC_END    0xfe800000UL
diff --git a/arch/arm/mach-ep93xx/simone.c b/arch/arm/mach-ep93xx/simone.c
new file mode 100644 (file)
index 0000000..cd93990
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * arch/arm/mach-ep93xx/simone.c
+ * Simplemachines Sim.One support.
+ *
+ * Copyright (C) 2010 Ryan Mallon <ryan@bluewatersys.com>
+ *
+ * Based on the 2.6.24.7 support:
+ *   Copyright (C) 2009 Simplemachines
+ *   MMC support by Peter Ivanov <ivanovp@gmail.com>, 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/physmap.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/i2c-gpio.h>
+
+#include <mach/hardware.h>
+#include <mach/fb.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+static struct physmap_flash_data simone_flash_data = {
+       .width          = 2,
+};
+
+static struct resource simone_flash_resource = {
+       .start          = EP93XX_CS6_PHYS_BASE,
+       .end            = EP93XX_CS6_PHYS_BASE + SZ_8M - 1,
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device simone_flash = {
+       .name           = "physmap-flash",
+       .id             = 0,
+       .num_resources  = 1,
+       .resource       = &simone_flash_resource,
+       .dev = {
+               .platform_data  = &simone_flash_data,
+       },
+};
+
+static struct ep93xx_eth_data simone_eth_data = {
+       .phy_id         = 1,
+};
+
+static struct ep93xxfb_mach_info simone_fb_info = {
+       .num_modes      = EP93XXFB_USE_MODEDB,
+       .bpp            = 16,
+       .flags          = EP93XXFB_USE_SDCSN0 | EP93XXFB_PCLK_FALLING,
+};
+
+static struct i2c_gpio_platform_data simone_i2c_gpio_data = {
+       .sda_pin                = EP93XX_GPIO_LINE_EEDAT,
+       .sda_is_open_drain      = 0,
+       .scl_pin                = EP93XX_GPIO_LINE_EECLK,
+       .scl_is_open_drain      = 0,
+       .udelay                 = 0,
+       .timeout                = 0,
+};
+
+static struct i2c_board_info __initdata simone_i2c_board_info[] = {
+       {
+               I2C_BOARD_INFO("ds1337", 0x68),
+       },
+};
+
+static void __init simone_init_machine(void)
+{
+       ep93xx_init_devices();
+
+       platform_device_register(&simone_flash);
+       ep93xx_register_eth(&simone_eth_data, 1);
+       ep93xx_register_fb(&simone_fb_info);
+       ep93xx_register_i2c(&simone_i2c_gpio_data, simone_i2c_board_info,
+                           ARRAY_SIZE(simone_i2c_board_info));
+}
+
+MACHINE_START(SIM_ONE, "Simplemachines Sim.One Board")
+/* Maintainer: Ryan Mallon <ryan@bluewatersys.com> */
+       .phys_io        = EP93XX_APB_PHYS_BASE,
+       .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+       .boot_params    = EP93XX_SDCE0_PHYS_BASE + 0x100,
+       .map_io         = ep93xx_map_io,
+       .init_irq       = ep93xx_init_irq,
+       .timer          = &ep93xx_timer,
+       .init_machine   = simone_init_machine,
+MACHINE_END
diff --git a/arch/arm/mach-ep93xx/snappercl15.c b/arch/arm/mach-ep93xx/snappercl15.c
new file mode 100644 (file)
index 0000000..51134b0
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * arch/arm/mach-ep93xx/snappercl15.c
+ * Bluewater Systems Snapper CL15 system module
+ *
+ * Copyright (C) 2009 Bluewater Systems Ltd
+ * Author: Ryan Mallon <ryan@bluewatersys.com>
+ *
+ * NAND code adapted from driver by:
+ *   Andre Renaud <andre@bluewatersys.com>
+ *   James R. McKaskill
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/i2c-gpio.h>
+#include <linux/fb.h>
+
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/nand.h>
+
+#include <mach/hardware.h>
+#include <mach/fb.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#define SNAPPERCL15_NAND_BASE  (EP93XX_CS7_PHYS_BASE + SZ_16M)
+
+#define SNAPPERCL15_NAND_WPN   (1 << 8)  /* Write protect (active low) */
+#define SNAPPERCL15_NAND_ALE   (1 << 9)  /* Address latch */
+#define SNAPPERCL15_NAND_CLE   (1 << 10) /* Command latch */
+#define SNAPPERCL15_NAND_CEN   (1 << 11) /* Chip enable (active low) */
+#define SNAPPERCL15_NAND_RDY   (1 << 14) /* Device ready */
+
+#define NAND_CTRL_ADDR(chip)   (chip->IO_ADDR_W + 0x40)
+
+static void snappercl15_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+                                     unsigned int ctrl)
+{
+       struct nand_chip *chip = mtd->priv;
+       static u16 nand_state = SNAPPERCL15_NAND_WPN;
+       u16 set;
+
+       if (ctrl & NAND_CTRL_CHANGE) {
+               set = SNAPPERCL15_NAND_CEN | SNAPPERCL15_NAND_WPN;
+
+               if (ctrl & NAND_NCE)
+                       set &= ~SNAPPERCL15_NAND_CEN;
+               if (ctrl & NAND_CLE)
+                       set |= SNAPPERCL15_NAND_CLE;
+               if (ctrl & NAND_ALE)
+                       set |= SNAPPERCL15_NAND_ALE;
+
+               nand_state &= ~(SNAPPERCL15_NAND_CEN |
+                               SNAPPERCL15_NAND_CLE |
+                               SNAPPERCL15_NAND_ALE);
+               nand_state |= set;
+               __raw_writew(nand_state, NAND_CTRL_ADDR(chip));
+       }
+
+       if (cmd != NAND_CMD_NONE)
+               __raw_writew((cmd & 0xff) | nand_state, chip->IO_ADDR_W);
+}
+
+static int snappercl15_nand_dev_ready(struct mtd_info *mtd)
+{
+       struct nand_chip *chip = mtd->priv;
+
+       return !!(__raw_readw(NAND_CTRL_ADDR(chip)) & SNAPPERCL15_NAND_RDY);
+}
+
+static const char *snappercl15_nand_part_probes[] = {"cmdlinepart", NULL};
+
+static struct mtd_partition snappercl15_nand_parts[] = {
+       {
+               .name           = "Kernel",
+               .offset         = 0,
+               .size           = SZ_2M,
+       },
+       {
+               .name           = "Filesystem",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = MTDPART_SIZ_FULL,
+       },
+};
+
+static struct platform_nand_data snappercl15_nand_data = {
+       .chip = {
+               .nr_chips               = 1,
+               .part_probe_types       = snappercl15_nand_part_probes,
+               .partitions             = snappercl15_nand_parts,
+               .nr_partitions          = ARRAY_SIZE(snappercl15_nand_parts),
+               .options                = NAND_NO_AUTOINCR,
+               .chip_delay             = 25,
+       },
+       .ctrl = {
+               .dev_ready              = snappercl15_nand_dev_ready,
+               .cmd_ctrl               = snappercl15_nand_cmd_ctrl,
+       },
+};
+
+static struct resource snappercl15_nand_resource[] = {
+       {
+               .start          = SNAPPERCL15_NAND_BASE,
+               .end            = SNAPPERCL15_NAND_BASE + SZ_4K - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device snappercl15_nand_device = {
+       .name                   = "gen_nand",
+       .id                     = -1,
+       .dev.platform_data      = &snappercl15_nand_data,
+       .resource               = snappercl15_nand_resource,
+       .num_resources          = ARRAY_SIZE(snappercl15_nand_resource),
+};
+
+static struct ep93xx_eth_data snappercl15_eth_data = {
+       .phy_id                 = 1,
+};
+
+static struct i2c_gpio_platform_data snappercl15_i2c_gpio_data = {
+       .sda_pin                = EP93XX_GPIO_LINE_EEDAT,
+       .sda_is_open_drain      = 0,
+       .scl_pin                = EP93XX_GPIO_LINE_EECLK,
+       .scl_is_open_drain      = 0,
+       .udelay                 = 0,
+       .timeout                = 0,
+};
+
+static struct i2c_board_info __initdata snappercl15_i2c_data[] = {
+       {
+               /* Audio codec */
+               I2C_BOARD_INFO("tlv320aic23", 0x1a),
+       },
+};
+
+static struct ep93xxfb_mach_info snappercl15_fb_info = {
+       .num_modes              = EP93XXFB_USE_MODEDB,
+       .bpp                    = 16,
+};
+
+static void __init snappercl15_init_machine(void)
+{
+       ep93xx_init_devices();
+       ep93xx_register_eth(&snappercl15_eth_data, 1);
+       ep93xx_register_i2c(&snappercl15_i2c_gpio_data, snappercl15_i2c_data,
+                           ARRAY_SIZE(snappercl15_i2c_data));
+       ep93xx_register_fb(&snappercl15_fb_info);
+       platform_device_register(&snappercl15_nand_device);
+}
+
+MACHINE_START(SNAPPER_CL15, "Bluewater Systems Snapper CL15")
+       /* Maintainer: Ryan Mallon <ryan@bluewatersys.com> */
+       .phys_io        = EP93XX_APB_PHYS_BASE,
+       .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+       .boot_params    = EP93XX_SDCE0_PHYS_BASE + 0x100,
+       .map_io         = ep93xx_map_io,
+       .init_irq       = ep93xx_init_irq,
+       .timer          = &ep93xx_timer,
+       .init_machine   = snappercl15_init_machine,
+MACHINE_END
index 41febc796b1c7e1564684eccc910516568fb54ad..e3bc3f6f6b105d42c8d4f73d33b4d5f92fc15a81 100644 (file)
@@ -32,12 +32,13 @@ unsigned int mem_fclk_21285 = 50000000;
 
 EXPORT_SYMBOL(mem_fclk_21285);
 
-static void __init early_fclk(char **arg)
+static int __init early_fclk(char *arg)
 {
-       mem_fclk_21285 = simple_strtoul(*arg, arg, 0);
+       mem_fclk_21285 = simple_strtoul(arg, NULL, 0);
+       return 0;
 }
 
-__early_param("mem_fclk_21285=", early_fclk);
+early_param("mem_fclk_21285", early_fclk);
 
 static int __init parse_tag_memclk(const struct tag *tag)
 {
index 4329b81235708637cb6bc003638f7c3090a5c9f2..60dda1318f2285785829c46c399889d5da495c89 100644 (file)
@@ -15,7 +15,7 @@
 
 #ifndef CONFIG_DEBUG_DC21285_PORT
        /* For NetWinder debugging */
-               .macro  addruart,rx
+               .macro  addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                 @ MMU enabled?
                moveq   \rx, #0x7c000000        @ physical
@@ -32,7 +32,7 @@
                .equ    dc21285_high, ARMCSR_BASE & 0xff000000
                .equ    dc21285_low,  ARMCSR_BASE & 0x00ffffff
 
-               .macro  addruart,rx
+               .macro  addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                 @ MMU enabled?
                moveq   \rx, #0x42000000
index d04a6eaeae14ad8e0545585c15b1a397c1e3a668..ad477047069ddc9188e33657f3ad0b5338b83e11 100644 (file)
@@ -11,7 +11,7 @@
  */
 #include <mach/hardware.h>
 
-       .macro  addruart,rx
+       .macro  addruart, rx, tmp
        mrc     p15, 0, \rx, c1, c0
        tst     \rx, #1                                 @ MMU enabled?
        ldreq   \rx, =GEMINI_UART_BASE                  @ physical
index 83e536d9436c02c7742edb78bd2906dbbc4338ca..45371eb86fcbf332020a9bb4a8e29a53b39b41ef 100644 (file)
@@ -7,4 +7,4 @@
  * (at your option) any later version.
  */
 
-#define VMALLOC_END    0xF0000000
+#define VMALLOC_END    0xf0000000UL
index 6294a1344dda80f81d89a1191f4a733ef4095f0f..a9ee8f0d48b7f6792ea5004844649c3acb3a5bd0 100644 (file)
@@ -14,7 +14,7 @@
                .equ    io_virt, IO_BASE
                .equ    io_phys, IO_START
 
-               .macro  addruart,rx
+               .macro  addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                @ MMU enabled?
                moveq   \rx, #io_phys          @ physical base address
index a0f60e55da6a8a2bb7c1cf05fc6bd889e605721f..8b390e36ba69db77a44fd228b6e17a1909b4ca8a 100644 (file)
@@ -144,8 +144,7 @@ static int __init integrator_init(void)
 {
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(lookups); i++)
-               clkdev_add(&lookups[i]);
+       clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
        for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
                struct amba_device *d = amba_devs[i];
index d347d659ea308c74edc6aa5870aae9b05e5f85d2..87a6888ae011ba71e3764f02ab97a1b74260e839 100644 (file)
@@ -11,7 +11,7 @@
  *
 */
 
-               .macro  addruart,rx
+               .macro  addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                 @ MMU enabled?
                moveq   \rx, #0x16000000        @ physical base address
index 3f35293d457a3cf0d44a6dc2ace58a918ea4c520..66ef86d6d9e3d0d80aa46f2e6f09d4314a491426 100644 (file)
@@ -558,9 +558,7 @@ static void __init intcp_init(void)
 {
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(cp_lookups); i++)
-               clkdev_add(&cp_lookups[i]);
-
+       clkdev_add_table(cp_lookups, ARRAY_SIZE(cp_lookups));
        platform_add_devices(intcp_devs, ARRAY_SIZE(intcp_devs));
 
        for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
index 9037d2e8557cbb163a07d2b47cbe967f959cf4fb..c9d6ba46963da99c4f5c8ede984a27f470238024 100644 (file)
@@ -11,7 +11,7 @@
  * published by the Free Software Foundation.
  */
 
-       .macro  addruart, rx
+       .macro  addruart, rx, tmp
        mrc     p15, 0, \rx, c1, c0
        tst     \rx, #1                 @ mmu enabled?
        moveq   \rx, #0xff000000        @ physical
index 52958099781400702fa380324148c842eefaa823..48642e66c5663007129db7bec7cd909e6749fa49 100644 (file)
@@ -61,9 +61,9 @@ void * __iomem __iop13xx_ioremap(unsigned long cookie, size_t size,
                                 (cookie - IOP13XX_PCIE_LOWER_MEM_RA));
                break;
        case IOP13XX_PBI_LOWER_MEM_RA ... IOP13XX_PBI_UPPER_MEM_RA:
-               retval = __arm_ioremap(IOP13XX_PBI_LOWER_MEM_PA +
+               retval = __arm_ioremap_caller(IOP13XX_PBI_LOWER_MEM_PA +
                                       (cookie - IOP13XX_PBI_LOWER_MEM_RA),
-                                      size, mtype);
+                                      size, mtype, __builtin_return_address(0));
                break;
        case IOP13XX_PCIE_LOWER_IO_PA ... IOP13XX_PCIE_UPPER_IO_PA:
                retval = (void *) IOP13XX_PCIE_IO_PHYS_TO_VIRT(cookie);
@@ -75,7 +75,8 @@ void * __iomem __iop13xx_ioremap(unsigned long cookie, size_t size,
                retval = (void *) IOP13XX_PMMR_PHYS_TO_VIRT(cookie);
                break;
        default:
-               retval = __arm_ioremap(cookie, size, mtype);
+               retval = __arm_ioremap_caller(cookie, size, mtype,
+                               __builtin_return_address(0));
        }
 
        return retval;
index 58b01664ffba5edc93f81e002bc79259f418b374..736afe1edd1f668c4f84850b1604a3fc98a699b2 100644 (file)
@@ -11,7 +11,7 @@
  * published by the Free Software Foundation.
  */
 
-               .macro  addruart, rx
+               .macro  addruart, rx, tmp
                mov     \rx, #0xfe000000        @ physical as well as virtual
                orr     \rx, \rx, #0x00800000   @ location of the UART
                .endm
index 85ceb09d85f031f9d77397a12d8c298130929b2c..c4862d48e583165bfb1ee2185a35742851a6ad71 100644 (file)
@@ -2,4 +2,4 @@
  * arch/arm/mach-iop32x/include/mach/vmalloc.h
  */
 
-#define VMALLOC_END    0xfe000000
+#define VMALLOC_END    0xfe000000UL
index a60c9ef05cc3cf16d3097ec94f1789b9e3097f7f..addb2da78422b0ff58df52a64dce48fe57bdd169 100644 (file)
@@ -11,7 +11,7 @@
  * published by the Free Software Foundation.
  */
 
-               .macro  addruart, rx
+               .macro  addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                 @ mmu enabled?
                moveq   \rx, #0xff000000        @ physical
index f9f99dea9bc44db39dd671bf66047077015856e0..48331dc2370411ca75db48058ea1ca8f5966a763 100644 (file)
@@ -2,4 +2,4 @@
  * arch/arm/mach-iop33x/include/mach/vmalloc.h
  */
 
-#define VMALLOC_END    0xfe000000
+#define VMALLOC_END    0xfe000000UL
index 904ff56d2246e9c91671b09dfdcee60598504f58..6a827681680fe20b833c07bc1990c488d1c20dae 100644 (file)
@@ -11,7 +11,7 @@
  *
 */
 
-               .macro  addruart,rx
+               .macro  addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                 @ MMU enabled?
                moveq   \rx, #0xc0000000        @ Physical base
index d195e35aed3bfe88a40ba18c9591433e63454883..61c8dae24f959f5311cc1c12ac651ca88fb2a67f 100644 (file)
@@ -17,4 +17,4 @@
  * The vmalloc() routines leaves a hole of 4kB between each vmalloced
  * area for the same reason. ;)
  */
-#define VMALLOC_END        0xfb000000
+#define VMALLOC_END        0xfb000000UL
index 905db3188724372ea1ff0ed0e5983050d1263fbf..a82e375465e283651c4f8e96ea7913c4a77f4b35 100644 (file)
@@ -12,7 +12,7 @@
  */
 #include <mach/ixp23xx.h>
 
-               .macro  addruart,rx
+               .macro  addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                         @ mmu enabled?
                ldreq   \rx, =IXP23XX_PERIPHERAL_PHYS   @ physical
index dd519f678d10fda041407d400ff5a732e0192ae1..896c56a1c00e4df2caa9a22192a2b6288cb3931a 100644 (file)
@@ -7,4 +7,4 @@
  * specific static I/O.
  */
 
-#define VMALLOC_END    (0xec000000)
+#define VMALLOC_END    (0xec000000UL)
index 3bbf40f6d964b277a7a153fa6a93e694c73ff9da..71728d36d501887f35fdff0ed67dd6714e2f9a3b 100644 (file)
@@ -426,6 +426,17 @@ static void __init ixp4xx_clocksource_init(void)
        clocksource_register(&clocksource_ixp4xx);
 }
 
+/*
+ * sched_clock()
+ */
+unsigned long long sched_clock(void)
+{
+       cycle_t cyc = ixp4xx_get_cycles(NULL);
+       struct clocksource *cs = &clocksource_ixp4xx;
+
+       return clocksource_cyc2ns(cyc, cs->mult, cs->shift);
+}
+
 /*
  * clockevents
  */
index 7c6a6912acdeef809e1e1296b187cf905c4d637a..893873eb2a0d9b584da49485af9819bdeac68ae9 100644 (file)
@@ -10,7 +10,7 @@
  * published by the Free Software Foundation.
 */
 
-                .macro  addruart,rx
+                .macro  addruart, rx, tmp
                 mrc     p15, 0, \rx, c1, c0
                 tst     \rx, #1                 @ MMU enabled?
                 moveq   \rx, #0xc8000000
index 7b3580b53adf3689a542d26670b550698d44bda4..9bcd64d59854559aad55acd19438d7c70927d4dc 100644 (file)
@@ -1,5 +1,5 @@
 /*
  * arch/arm/mach-ixp4xx/include/mach/vmalloc.h
  */
-#define VMALLOC_END       (0xFF000000)
+#define VMALLOC_END       (0xff000000UL)
 
index a4a55c199d77638d92f8b48b62a8e9e39cbfa8c3..d0606774dea7de3baa03e4291dd016b0825dde07 100644 (file)
@@ -8,7 +8,7 @@
 
 #include <mach/bridge-regs.h>
 
-       .macro  addruart,rx
+       .macro  addruart, rx, tmp
        mrc     p15, 0, \rx, c1, c0
        tst     \rx, #1                                 @ MMU enabled?
        ldreq   \rx, =KIRKWOOD_REGS_PHYS_BASE
index 8f48260dcdadbe6ea3eeeef07b3c13d12d2a75a7..bf162ca3d2c16b625f819fb6cdc3bb4be43a38d1 100644 (file)
@@ -2,4 +2,4 @@
  * arch/arm/mach-kirkwood/include/mach/vmalloc.h
  */
 
-#define VMALLOC_END    0xfe800000
+#define VMALLOC_END    0xfe800000UL
index 3782c3559497e52464d0aca8ba56a917b8198078..cf2095da2372cddfb0e3105f1ab04ac4fc4fc61c 100644 (file)
@@ -14,7 +14,7 @@
 #include <mach/hardware.h>
 #include <mach/regs-uart.h>
 
-       .macro  addruart, rx
+       .macro  addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                         @ MMU enabled?
                ldreq   \rx, =KS8695_UART_PA            @ physical base address
index 34eed2a63e69951eda7db9f8ea291dd04ba5be1b..b69ed344c7c981a4c6b94e2564a16be411849401 100644 (file)
@@ -14,7 +14,7 @@
                .equ    io_virt, IO_BASE
                .equ    io_phys, IO_START
 
-               .macro  addruart,rx
+               .macro  addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                 @ MMU enabled?
                moveq   \rx, #io_phys           @ physical base address
index 85141ed5383d1c355af041622099d545c5c1dfef..c0dcbbba22ba6f7eeb0af9893579f7aedc870879 100644 (file)
@@ -14,7 +14,7 @@
        @ It is not known if this will be appropriate for every 40x
        @ board.
 
-               .macro  addruart,rx
+               .macro  addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                 @ MMU enabled?
                mov     \rx, #0x00000700        @ offset from base
index 3fbd49490bb9d7290165aba3e6d67fa425d41a4e..d62da7358b16c05ad716cb7d91dabfbce914721a 100644 (file)
@@ -7,4 +7,4 @@
  *  version 2 as published by the Free Software Foundation.
  *
  */
-#define VMALLOC_END       (0xe8000000)
+#define VMALLOC_END       (0xe8000000UL)
index a8c20bd2f9514d87ca5acef76b0ce75ddf250d05..3136c913a92c2c4886cbcd232f145f9aac2572f2 100644 (file)
@@ -8,7 +8,7 @@
 
 #include <mach/loki.h>
 
-       .macro  addruart,rx
+       .macro  addruart, rx, tmp
        mrc     p15, 0, \rx, c1, c0
        tst     \rx, #1                                 @ MMU enabled?
        ldreq   \rx, =LOKI_REGS_PHYS_BASE
index 8dc3bfcbf9f07eb1754411d4ca82adfade746200..5dcbd865443f0bae5415dc5288d195854c1178a0 100644 (file)
@@ -2,4 +2,4 @@
  * arch/arm/mach-loki/include/mach/vmalloc.h
  */
 
-#define VMALLOC_END    0xfe800000
+#define VMALLOC_END    0xfe800000UL
index 2a46ed5cc2a297e0356529b7465e0a8c52a06231..886e05648f08a5a4975bc0257b2b0929e9fffc1f 100644 (file)
@@ -88,11 +88,3 @@ unsigned long clk_get_rate(struct clk *clk)
        return rate;
 }
 EXPORT_SYMBOL(clk_get_rate);
-
-void clks_register(struct clk_lookup *clks, size_t num)
-{
-       int i;
-
-       for (i = 0; i < num; i++)
-               clkdev_add(&clks[i]);
-}
index eefffbe683b0263e4c053833b7f1025b3ed83f27..016ae94691c04cd42838c9b0af352b68a6e7cacc 100644 (file)
@@ -68,5 +68,3 @@ struct clk clk_##_name = {                                    \
 
 extern struct clk clk_pxa168_gpio;
 extern struct clk clk_pxa168_timers;
-
-extern void clks_register(struct clk_lookup *, size_t);
index a850f87de51d90c68030f5dd5e256a33d69382af..76deff238e1c5f394505a0a413d3fb98577d0645 100644 (file)
@@ -11,7 +11,7 @@
 
 #include <mach/addr-map.h>
 
-               .macro  addruart,rx
+               .macro  addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                         @ MMU enabled?
                ldreq   \rx, =APB_PHYS_BASE             @ physical
index b60ccaf9fee75dff3da8e152c8d69e72dc002351..1d0bac003ad0bb984b1430e9ba01531b37777bf7 100644 (file)
@@ -2,4 +2,4 @@
  * linux/arch/arm/mach-mmp/include/mach/vmalloc.h
  */
 
-#define VMALLOC_END    0xfe000000
+#define VMALLOC_END    0xfe000000UL
index 37dbdde17fac5b83bc739edc5b0493986fd9bf9c..1873c821df9051ebd37fe65a154ed437cb8a3608 100644 (file)
@@ -94,7 +94,7 @@ static int __init pxa168_init(void)
                mfp_init_base(MFPR_VIRT_BASE);
                mfp_init_addr(pxa168_mfp_addr_map);
                pxa_init_dma(IRQ_PXA168_DMA_INT0, 32);
-               clks_register(ARRAY_AND_SIZE(pxa168_clkregs));
+               clkdev_add_table(ARRAY_AND_SIZE(pxa168_clkregs));
        }
 
        return 0;
index d4049508a4df5cf71725bca0178f2ab754fce7bb..46f2d69bef3cf01dd3778a380fa2b1801799cef1 100644 (file)
@@ -131,7 +131,7 @@ static int __init pxa910_init(void)
                mfp_init_base(MFPR_VIRT_BASE);
                mfp_init_addr(pxa910_mfp_addr_map);
                pxa_init_dma(IRQ_PXA910_DMA_INT0, 32);
-               clks_register(ARRAY_AND_SIZE(pxa910_clkregs));
+               clkdev_add_table(ARRAY_AND_SIZE(pxa910_clkregs));
        }
 
        return 0;
index d48747ebcd3dc64be6df5bbd0409a5e6705f43bf..528750f307e9428433c97101153be1933d495ba8 100644 (file)
@@ -20,7 +20,7 @@
 #include <mach/msm_iomap.h>
 
 #ifdef CONFIG_MSM_DEBUG_UART
-       .macro  addruart,rx
+       .macro  addruart, rx, tmp
        @ see if the MMU is enabled and select appropriate base address
        mrc     p15, 0, \rx, c1, c0
        tst     \rx, #1
@@ -40,7 +40,7 @@
        beq     1001b
        .endm
 #else
-       .macro  addruart,rx
+       .macro  addruart, rx, tmp
        .endm
 
        .macro  senduart,rd,rx
index 1c5e7dac086f1892d9a6c831f8d5cf99dee90453..05f96b780aa6a811584fa3d25cfc4e2ce5ce6e0f 100644 (file)
@@ -76,5 +76,6 @@ __msm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
                        mtype = MT_DEVICE_NONSHARED;
        }
 
-       return __arm_ioremap(phys_addr, size, mtype);
+       return __arm_ioremap_caller(phys_addr, size, mtype,
+               __builtin_return_address(0));
 }
index a06442fbd3415b9bd935daf71b809685cc36e75c..cd81689c4621dad5bfa9b08d2b1a35bed5049b8a 100644 (file)
@@ -8,7 +8,7 @@
 
 #include <mach/mv78xx0.h>
 
-       .macro  addruart,rx
+       .macro  addruart, rx, tmp
        mrc     p15, 0, \rx, c1, c0
        tst     \rx, #1                                 @ MMU enabled?
        ldreq   \rx, =MV78XX0_REGS_PHYS_BASE
index 1c4954386a847beeec73102dd0fbafff730e05c7..ba26fe98e640097371b348d34a1d6c49ce53e529 100644 (file)
@@ -2,4 +2,4 @@
  * arch/arm/mach-mv78xx0/include/mach/vmalloc.h
  */
 
-#define VMALLOC_END    0xfe000000
+#define VMALLOC_END    0xfe000000UL
index d1b588519ad23b8dc230fb343d8b3596b99f3c96..6cf2d4a7511dc441561c80fe80ca432cf886d3b5 100644 (file)
@@ -570,7 +570,6 @@ static struct clk_lookup lookups[] __initdata = {
 int __init mx1_clocks_init(unsigned long fref)
 {
        unsigned int reg;
-       int i;
 
        /* disable clocks we are able to */
        __raw_writel(0, SCM_GCCR);
@@ -592,8 +591,7 @@ int __init mx1_clocks_init(unsigned long fref)
        reg = (reg & CCM_CSCR_CLKO_MASK) >> CCM_CSCR_CLKO_OFFSET;
        clko_clk.parent = (struct clk *)clko_clocks[reg];
 
-       for (i = 0; i < ARRAY_SIZE(lookups); i++)
-               clkdev_add(&lookups[i]);
+       clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
        clk_enable(&hclk);
        clk_enable(&fclk);
index 91901b5d56c2e63a871da04fbb489140f83ec3ea..e82b489d12150fd8a80c362b744538fcb494dca3 100644 (file)
@@ -968,7 +968,6 @@ static struct clk_lookup lookups[] = {
  */
 int __init mx21_clocks_init(unsigned long lref, unsigned long href)
 {
-       int i;
        u32 cscr;
 
        external_low_reference = lref;
@@ -986,8 +985,7 @@ int __init mx21_clocks_init(unsigned long lref, unsigned long href)
        else
                spll_clk.parent = &fpm_clk;
 
-       for (i = 0; i < ARRAY_SIZE(lookups); i++)
-               clkdev_add(&lookups[i]);
+       clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
        /* Turn off all clock gates */
        __raw_writel(0, CCM_PCCR0);
index b010bf9ceaaba1f4d18168fccdc31de2d7d26d2e..18c53a6487fafc7234d37cc494f04ff6c7250c49 100644 (file)
@@ -719,7 +719,6 @@ static void __init to2_adjust_clocks(void)
 int __init mx27_clocks_init(unsigned long fref)
 {
        u32 cscr = __raw_readl(CCM_CSCR);
-       int i;
 
        external_high_reference = fref;
 
@@ -736,8 +735,7 @@ int __init mx27_clocks_init(unsigned long fref)
 
        to2_adjust_clocks();
 
-       for (i = 0; i < ARRAY_SIZE(lookups); i++)
-               clkdev_add(&lookups[i]);
+       clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
        /* Turn off all clocks we do not need */
        __raw_writel(0, CCM_PCCR0);
index 6acc88bcdc403f415ff8526228e7ebca92303792..37e1359ad0c0596ac8193e7d1263c11550250c4e 100644 (file)
@@ -218,10 +218,7 @@ static struct clk_lookup lookups[] = {
 
 int __init mx25_clocks_init(void)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(lookups); i++)
-               clkdev_add(&lookups[i]);
+       clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
        /* Turn off all clocks except the ones we need to survive, namely:
         * EMI, GPIO1-3 (CCM_CGCR1[18:16]), GPT1, IOMUXC (CCM_CGCR1[27]), IIM,
index 7584b4c6c556d6a23d3d7fa30567d0de4fdbd6c3..f3f41fa4f21bd4541400082519b5b449a8bfa696 100644 (file)
@@ -485,15 +485,13 @@ static struct clk_lookup lookups[] = {
 
 int __init mx35_clocks_init()
 {
-       int i;
        unsigned int ll = 0;
 
 #if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_ICEDCC)
        ll = (3 << 16);
 #endif
 
-       for (i = 0; i < ARRAY_SIZE(lookups); i++)
-               clkdev_add(&lookups[i]);
+       clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
        /* Turn off all clocks except the ones we need to survive, namely:
         * EMI, GPIO1/2/3, GPT, IOMUX, MAX and eventually uart
index 27a318af0d200640215a7ef01c1272119ea69748..b5c39a016db78a6459a4edc8b4f5153db6f45582 100644 (file)
@@ -578,12 +578,10 @@ static struct clk_lookup lookups[] = {
 int __init mx31_clocks_init(unsigned long fref)
 {
        u32 reg;
-       int i;
 
        ckih_rate = fref;
 
-       for (i = 0; i < ARRAY_SIZE(lookups); i++)
-               clkdev_add(&lookups[i]);
+       clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
        /* change the csi_clk parent if necessary */
        reg = __raw_readl(MXC_CCM_CCMR);
index ecfa37fef8ade52accc9f14a0839d4f6af9afea0..5c85075d8a56b9b6c40059785dd9a4cd69658632 100644 (file)
@@ -624,7 +624,6 @@ static struct clk_lookup lookups[] = {
 int __init mxc91231_clocks_init(unsigned long fref)
 {
        void __iomem *gpt_base;
-       int i;
 
        ckih_rate = fref;
 
@@ -632,8 +631,7 @@ int __init mxc91231_clocks_init(unsigned long fref)
        sdhc_clk[0].parent = clk_sdhc_parent(&sdhc_clk[0]);
        sdhc_clk[1].parent = clk_sdhc_parent(&sdhc_clk[1]);
 
-       for (i = 0; i < ARRAY_SIZE(lookups); i++)
-               clkdev_add(&lookups[i]);
+       clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
        gpt_base = MXC91231_IO_ADDRESS(MXC91231_GPT1_BASE_ADDR);
        mxc_timer_init(&gpt_clk, gpt_base, MXC91231_INT_GPT);
index 11b9d5b46390daf54a2294c1925a832d3ecfb330..e96339e71d88fec6cbf56e72f08ba9d0dd4d9008 100644 (file)
@@ -13,7 +13,7 @@
 
 #include "hardware.h"
 
-               .macro  addruart,rx
+               .macro  addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                 @ MMU enabled?
                moveq   \rx, #0x00100000                @ physical
index e876990e156971def6d5e7304cc2d6914b1ba2cd..4f92acfba9545aaf5f9043925b51d8fcd1334ac0 100644 (file)
@@ -10,7 +10,7 @@
  *
 */
 
-               .macro  addruart,rx
+               .macro  addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                 @ MMU enabled?
                moveq   \rx, #0x10000000        @ physical base address
index be12e31ea52886d520eb88fcdd39fbdc5725f6fe..f83d574d9445728ec374d96db6decf288a47cab2 100644 (file)
@@ -1,2 +1,2 @@
 
-#define VMALLOC_END       0xe8000000
+#define VMALLOC_END       0xe8000000UL
index c9530fba00aa54866ffdba2372a1324bcd8bea4b..0859336a8e6d1be71a8090c1e8ef53b1640c87bc 100644 (file)
@@ -11,7 +11,7 @@
 
 #include <mach/regs-board-a9m9750dev.h>
 
-               .macro  addruart,rx
+               .macro  addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1
                ldreq   \rx, =NS9XXX_CSxSTAT_PHYS(0)
index fe964d3bcc477d9710c6929f8a41d3da6fc52f08..c8651974c4b0f0a3a2c9560cbcb17e95cc8eb606 100644 (file)
@@ -11,6 +11,6 @@
 #ifndef __ASM_ARCH_VMALLOC_H
 #define __ASM_ARCH_VMALLOC_H
 
-#define VMALLOC_END     (0xf0000000)
+#define VMALLOC_END     (0xf0000000UL)
 
 #endif /* ifndef __ASM_ARCH_VMALLOC_H */
diff --git a/arch/arm/mach-nuc93x/Kconfig b/arch/arm/mach-nuc93x/Kconfig
new file mode 100644 (file)
index 0000000..2bc40a2
--- /dev/null
@@ -0,0 +1,19 @@
+if ARCH_NUC93X
+
+config CPU_NUC932
+       bool
+       help
+         Support for NUC932 of Nuvoton NUC93X CPUs.
+
+menu "NUC932 Machines"
+
+config MACH_NUC932EVB
+       bool "Nuvoton NUC932 Evaluation Board"
+       default y
+       select CPU_NUC932
+       help
+          Say Y here if you are using the Nuvoton NUC932EVB
+
+endmenu
+
+endif
diff --git a/arch/arm/mach-nuc93x/Makefile b/arch/arm/mach-nuc93x/Makefile
new file mode 100644 (file)
index 0000000..440e2de
--- /dev/null
@@ -0,0 +1,14 @@
+#
+# Makefile for the linux kernel.
+#
+
+# Object file lists.
+
+obj-y                          := irq.o time.o dev.o cpu.o clock.o
+# NUC932 CPU support files
+
+obj-$(CONFIG_CPU_NUC932)       += nuc932.o
+
+# machine support
+
+obj-$(CONFIG_MACH_NUC932EVB)   += mach-nuc932evb.o
diff --git a/arch/arm/mach-nuc93x/Makefile.boot b/arch/arm/mach-nuc93x/Makefile.boot
new file mode 100644 (file)
index 0000000..a057b54
--- /dev/null
@@ -0,0 +1,3 @@
+zreladdr-y     := 0x00008000
+params_phys-y  := 0x00000100
+
diff --git a/arch/arm/mach-nuc93x/clock.c b/arch/arm/mach-nuc93x/clock.c
new file mode 100644 (file)
index 0000000..0521efb
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * linux/arch/arm/mach-nuc93x/clock.c
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/clk.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+
+#include "clock.h"
+
+static DEFINE_SPINLOCK(clocks_lock);
+
+int clk_enable(struct clk *clk)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&clocks_lock, flags);
+       if (clk->enabled++ == 0)
+               (clk->enable)(clk, 1);
+       spin_unlock_irqrestore(&clocks_lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+       unsigned long flags;
+
+       WARN_ON(clk->enabled == 0);
+
+       spin_lock_irqsave(&clocks_lock, flags);
+       if (--clk->enabled == 0)
+               (clk->enable)(clk, 0);
+       spin_unlock_irqrestore(&clocks_lock, flags);
+}
+EXPORT_SYMBOL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+       return 27000000;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+void nuc93x_clk_enable(struct clk *clk, int enable)
+{
+       unsigned int clocks = clk->cken;
+       unsigned long clken;
+
+       clken = __raw_readl(NUC93X_VA_CLKPWR);
+
+       if (enable)
+               clken |= clocks;
+       else
+               clken &= ~clocks;
+
+       __raw_writel(clken, NUC93X_VA_CLKPWR);
+}
+
+void clks_register(struct clk_lookup *clks, size_t num)
+{
+       int i;
+
+       for (i = 0; i < num; i++)
+               clkdev_add(&clks[i]);
+}
diff --git a/arch/arm/mach-nuc93x/clock.h b/arch/arm/mach-nuc93x/clock.h
new file mode 100644 (file)
index 0000000..18e51be
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * linux/arch/arm/mach-nuc93x/clock.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ */
+
+#include <asm/clkdev.h>
+
+void nuc93x_clk_enable(struct clk *clk, int enable);
+void clks_register(struct clk_lookup *clks, size_t num);
+
+struct clk {
+       unsigned long           cken;
+       unsigned int            enabled;
+       void                    (*enable)(struct clk *, int enable);
+};
+
+#define DEFINE_CLK(_name, _ctrlbit)                    \
+struct clk clk_##_name = {                             \
+               .enable = nuc93x_clk_enable,            \
+               .cken   = (1 << _ctrlbit),              \
+       }
+
+#define DEF_CLKLOOK(_clk, _devname, _conname)          \
+       {                                               \
+               .clk            = _clk,                 \
+               .dev_id         = _devname,             \
+               .con_id         = _conname,             \
+       }
+
diff --git a/arch/arm/mach-nuc93x/cpu.c b/arch/arm/mach-nuc93x/cpu.c
new file mode 100644 (file)
index 0000000..f6ff5d8
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * linux/arch/arm/mach-nuc93x/cpu.c
+ *
+ * Copyright (c) 2009 Nuvoton corporation.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * NUC93x series cpu common support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation;version 2 of the License.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/serial_8250.h>
+#include <linux/delay.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+#include <asm/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/regs-serial.h>
+#include <mach/regs-clock.h>
+#include <mach/regs-ebi.h>
+
+#include "cpu.h"
+#include "clock.h"
+
+/* Initial IO mappings */
+
+static struct map_desc nuc93x_iodesc[] __initdata = {
+       IODESC_ENT(IRQ),
+       IODESC_ENT(GCR),
+       IODESC_ENT(UART),
+       IODESC_ENT(TIMER),
+       IODESC_ENT(EBI),
+};
+
+/* Initial nuc932 clock declarations. */
+static DEFINE_CLK(audio, 2);
+static DEFINE_CLK(sd, 3);
+static DEFINE_CLK(jpg, 4);
+static DEFINE_CLK(video, 5);
+static DEFINE_CLK(vpost, 6);
+static DEFINE_CLK(2d, 7);
+static DEFINE_CLK(gpu, 8);
+static DEFINE_CLK(gdma, 9);
+static DEFINE_CLK(adc, 10);
+static DEFINE_CLK(uart, 11);
+static DEFINE_CLK(spi, 12);
+static DEFINE_CLK(pwm, 13);
+static DEFINE_CLK(timer, 14);
+static DEFINE_CLK(wdt, 15);
+static DEFINE_CLK(ac97, 16);
+static DEFINE_CLK(i2s, 16);
+static DEFINE_CLK(usbck, 17);
+static DEFINE_CLK(usb48, 18);
+static DEFINE_CLK(usbh, 19);
+static DEFINE_CLK(i2c, 20);
+static DEFINE_CLK(ext, 0);
+
+static struct clk_lookup nuc932_clkregs[] = {
+       DEF_CLKLOOK(&clk_audio, "nuc932-audio", NULL),
+       DEF_CLKLOOK(&clk_sd, "nuc932-sd", NULL),
+       DEF_CLKLOOK(&clk_jpg, "nuc932-jpg", "NULL"),
+       DEF_CLKLOOK(&clk_video, "nuc932-video", "NULL"),
+       DEF_CLKLOOK(&clk_vpost, "nuc932-vpost", NULL),
+       DEF_CLKLOOK(&clk_2d, "nuc932-2d", NULL),
+       DEF_CLKLOOK(&clk_gpu, "nuc932-gpu", NULL),
+       DEF_CLKLOOK(&clk_gdma, "nuc932-gdma", "NULL"),
+       DEF_CLKLOOK(&clk_adc, "nuc932-adc", NULL),
+       DEF_CLKLOOK(&clk_uart, NULL, "uart"),
+       DEF_CLKLOOK(&clk_spi, "nuc932-spi", NULL),
+       DEF_CLKLOOK(&clk_pwm, "nuc932-pwm", NULL),
+       DEF_CLKLOOK(&clk_timer, NULL, "timer"),
+       DEF_CLKLOOK(&clk_wdt, "nuc932-wdt", NULL),
+       DEF_CLKLOOK(&clk_ac97, "nuc932-ac97", NULL),
+       DEF_CLKLOOK(&clk_i2s, "nuc932-i2s", NULL),
+       DEF_CLKLOOK(&clk_usbck, "nuc932-usbck", NULL),
+       DEF_CLKLOOK(&clk_usb48, "nuc932-usb48", NULL),
+       DEF_CLKLOOK(&clk_usbh, "nuc932-usbh", NULL),
+       DEF_CLKLOOK(&clk_i2c, "nuc932-i2c", NULL),
+       DEF_CLKLOOK(&clk_ext, NULL, "ext"),
+};
+
+/* Initial serial platform data */
+
+struct plat_serial8250_port nuc93x_uart_data[] = {
+       NUC93X_8250PORT(UART0),
+       {},
+};
+
+struct platform_device nuc93x_serial_device = {
+       .name                   = "serial8250",
+       .id                     = PLAT8250_DEV_PLATFORM,
+       .dev                    = {
+               .platform_data  = nuc93x_uart_data,
+       },
+};
+
+/*Init NUC93x evb io*/
+
+void __init nuc93x_map_io(struct map_desc *mach_desc, int mach_size)
+{
+       unsigned long idcode = 0x0;
+
+       iotable_init(mach_desc, mach_size);
+       iotable_init(nuc93x_iodesc, ARRAY_SIZE(nuc93x_iodesc));
+
+       idcode = __raw_readl(NUC93XPDID);
+       if (idcode == NUC932_CPUID)
+               printk(KERN_INFO "CPU type 0x%08lx is NUC910\n", idcode);
+       else
+               printk(KERN_ERR "CPU type detect error!\n");
+
+}
+
+/*Init NUC93x clock*/
+
+void __init nuc93x_init_clocks(void)
+{
+       clks_register(nuc932_clkregs, ARRAY_SIZE(nuc932_clkregs));
+}
+
diff --git a/arch/arm/mach-nuc93x/cpu.h b/arch/arm/mach-nuc93x/cpu.h
new file mode 100644 (file)
index 0000000..9def281
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * arch/arm/mach-nuc93x/cpu.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * Header file for NUC93X CPU support
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#define IODESC_ENT(y)                                  \
+{                                                      \
+       .virtual = (unsigned long)NUC93X_VA_##y,        \
+       .pfn     = __phys_to_pfn(NUC93X_PA_##y),        \
+       .length  = NUC93X_SZ_##y,                       \
+       .type    = MT_DEVICE,                           \
+}
+
+#define NUC93X_8250PORT(name)                                  \
+{                                                              \
+       .membase        = name##_BA,                            \
+       .mapbase        = name##_PA,                            \
+       .irq            = IRQ_##name,                           \
+       .uartclk        = 57139200,                             \
+       .regshift       = 2,                                    \
+       .iotype         = UPIO_MEM,                             \
+       .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,    \
+}
+
+/*Cpu identifier register*/
+
+#define NUC93XPDID     NUC93X_VA_GCR
+#define NUC932_CPUID   0x29550091
+
+/* extern file from cpu.c */
+
+extern void nuc93x_clock_source(struct device *dev, unsigned char *src);
+extern void nuc93x_init_clocks(void);
+extern void nuc93x_map_io(struct map_desc *mach_desc, int mach_size);
+extern void nuc93x_board_init(struct platform_device **device, int size);
+extern struct platform_device nuc93x_serial_device;
+
diff --git a/arch/arm/mach-nuc93x/dev.c b/arch/arm/mach-nuc93x/dev.c
new file mode 100644 (file)
index 0000000..a962ae9
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * linux/arch/arm/mach-nuc93x/dev.c
+ *
+ * Copyright (C) 2009 Nuvoton corporation.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation;version 2 of the License.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+#include <asm/mach-types.h>
+
+#include "cpu.h"
+
+/*Here should be your evb resourse,such as LCD*/
+
+static struct platform_device *nuc93x_public_dev[] __initdata = {
+       &nuc93x_serial_device,
+};
+
+/* Provide adding specific CPU platform devices API */
+
+void __init nuc93x_board_init(struct platform_device **device, int size)
+{
+       platform_add_devices(device, size);
+       platform_add_devices(nuc93x_public_dev, ARRAY_SIZE(nuc93x_public_dev));
+}
+
diff --git a/arch/arm/mach-nuc93x/include/mach/clkdev.h b/arch/arm/mach-nuc93x/include/mach/clkdev.h
new file mode 100644 (file)
index 0000000..04b37a8
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __ASM_MACH_CLKDEV_H
+#define __ASM_MACH_CLKDEV_H
+
+#define __clk_get(clk) ({ 1; })
+#define __clk_put(clk) do { } while (0)
+
+#endif
diff --git a/arch/arm/mach-nuc93x/include/mach/entry-macro.S b/arch/arm/mach-nuc93x/include/mach/entry-macro.S
new file mode 100644 (file)
index 0000000..1352cbd
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * arch/arm/mach-nuc93x/include/mach/entry-macro.S
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ *
+ */
+
+#include <mach/hardware.h>
+#include <mach/regs-irq.h>
+
+       .macro  get_irqnr_preamble, base, tmp
+       .endm
+
+       .macro  arch_ret_to_user, tmp1, tmp2
+       .endm
+
+       .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
+
+               mov     \base, #AIC_BA
+
+               ldr     \irqnr, [ \base, #AIC_IPER]
+               ldr     \irqnr, [ \base, #AIC_ISNR]
+               cmp     \irqnr, #0
+
+       .endm
+
+       /* currently don't need an disable_fiq macro */
+
+       .macro  disable_fiq
+       .endm
diff --git a/arch/arm/mach-nuc93x/include/mach/hardware.h b/arch/arm/mach-nuc93x/include/mach/hardware.h
new file mode 100644 (file)
index 0000000..fb5c6fc
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * arch/arm/mach-nuc93x/include/mach/hardware.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <asm/sizes.h>
+#include <mach/map.h>
+
+#endif /* __ASM_ARCH_HARDWARE_H */
diff --git a/arch/arm/mach-nuc93x/include/mach/io.h b/arch/arm/mach-nuc93x/include/mach/io.h
new file mode 100644 (file)
index 0000000..72e5051
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * arch/arm/mach-nuc93x/include/mach/io.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+/*
+ * 1:1 mapping for ioremapped regions.
+ */
+
+#define __mem_pci(a)   (a)
+#define __io(a)                __typesafe_io(a)
+
+#endif
diff --git a/arch/arm/mach-nuc93x/include/mach/irqs.h b/arch/arm/mach-nuc93x/include/mach/irqs.h
new file mode 100644 (file)
index 0000000..7c4aa71
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * arch/arm/mach-nuc93x/include/mach/irqs.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation;version 2 of the License.
+ *
+ */
+
+#ifndef __ASM_ARCH_IRQS_H
+#define __ASM_ARCH_IRQS_H
+
+#define NUC93X_IRQ(x)  (x)
+
+/* Main cpu interrupts */
+
+#define IRQ_WDT                NUC93X_IRQ(1)
+#define IRQ_IRQ0       NUC93X_IRQ(2)
+#define IRQ_IRQ1       NUC93X_IRQ(3)
+#define IRQ_IRQ2       NUC93X_IRQ(4)
+#define IRQ_IRQ3       NUC93X_IRQ(5)
+#define IRQ_USBH       NUC93X_IRQ(6)
+#define IRQ_APU                NUC93X_IRQ(7)
+#define IRQ_VPOST      NUC93X_IRQ(8)
+#define IRQ_ADC                NUC93X_IRQ(9)
+#define IRQ_UART0      NUC93X_IRQ(10)
+#define IRQ_TIMER0     NUC93X_IRQ(11)
+#define IRQ_GPU0       NUC93X_IRQ(12)
+#define IRQ_GPU1       NUC93X_IRQ(13)
+#define IRQ_GPU2       NUC93X_IRQ(14)
+#define IRQ_GPU3       NUC93X_IRQ(15)
+#define IRQ_GPU4       NUC93X_IRQ(16)
+#define IRQ_VIN                NUC93X_IRQ(17)
+#define IRQ_USBD       NUC93X_IRQ(18)
+#define IRQ_VRAMLD     NUC93X_IRQ(19)
+#define IRQ_GDMA0      NUC93X_IRQ(20)
+#define IRQ_GDMA1      NUC93X_IRQ(21)
+#define IRQ_SDIO       NUC93X_IRQ(22)
+#define IRQ_FMI                NUC93X_IRQ(22)
+#define IRQ_JPEG       NUC93X_IRQ(23)
+#define IRQ_SPI0       NUC93X_IRQ(24)
+#define IRQ_SPI1       NUC93X_IRQ(25)
+#define IRQ_RTC                NUC93X_IRQ(26)
+#define IRQ_PWM0       NUC93X_IRQ(27)
+#define IRQ_PWM1       NUC93X_IRQ(28)
+#define IRQ_PWM2       NUC93X_IRQ(29)
+#define IRQ_PWM3       NUC93X_IRQ(30)
+#define IRQ_I2SAC97    NUC93X_IRQ(31)
+#define IRQ_CAP0       IRQ_PWM0
+#define IRQ_CAP1       IRQ_PWM1
+#define IRQ_CAP2       IRQ_PWM2
+#define IRQ_CAP3       IRQ_PWM3
+#define NR_IRQS                (IRQ_I2SAC97 + 1)
+
+#endif /* __ASM_ARCH_IRQ_H */
diff --git a/arch/arm/mach-nuc93x/include/mach/map.h b/arch/arm/mach-nuc93x/include/mach/map.h
new file mode 100644 (file)
index 0000000..fd0b5e8
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * arch/arm/mach-nuc93x/include/mach/map.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation;version 2 of the License.
+ *
+ */
+
+#ifndef __ASM_ARCH_MAP_H
+#define __ASM_ARCH_MAP_H
+
+#define MAP_OFFSET     (0xfff00000)
+#define CLK_OFFSET     (0x10)
+
+#ifndef __ASSEMBLY__
+#define NUC93X_ADDR(x) ((void __iomem *)(0xF0000000 + ((x)&(~MAP_OFFSET))))
+#else
+#define NUC93X_ADDR(x) (0xF0000000 + ((x)&(~MAP_OFFSET)))
+#endif
+
+ /*
+  * nuc932 hardware register definition
+  */
+
+#define NUC93X_PA_IRQ          (0xFFF83000)
+#define NUC93X_PA_GCR          (0xFFF00000)
+#define NUC93X_PA_EBI          (0xFFF01000)
+#define NUC93X_PA_UART         (0xFFF80000)
+#define NUC93X_PA_TIMER                (0xFFF81000)
+#define NUC93X_PA_GPIO         (0xFFF84000)
+#define NUC93X_PA_GDMA         (0xFFF03000)
+#define NUC93X_PA_USBHOST      (0xFFF0d000)
+#define NUC93X_PA_I2C          (0xFFF89000)
+#define NUC93X_PA_LCD          (0xFFF06000)
+#define NUC93X_PA_GE           (0xFFF05000)
+#define NUC93X_PA_ADC          (0xFFF85000)
+#define NUC93X_PA_RTC          (0xFFF87000)
+#define NUC93X_PA_PWM          (0xFFF82000)
+#define NUC93X_PA_ACTL         (0xFFF0a000)
+#define NUC93X_PA_USBDEV       (0xFFF0C000)
+#define NUC93X_PA_JEPEG                (0xFFF0e000)
+#define NUC93X_PA_CACHE_T      (0xFFF60000)
+#define NUC93X_PA_VRAM         (0xFFF0b000)
+#define NUC93X_PA_DMAC         (0xFFF09000)
+#define NUC93X_PA_I2SM         (0xFFF08000)
+#define NUC93X_PA_CACHE                (0xFFF02000)
+#define NUC93X_PA_GPU          (0xFFF04000)
+#define NUC93X_PA_VIDEOIN      (0xFFF07000)
+#define NUC93X_PA_SPI0         (0xFFF86000)
+#define NUC93X_PA_SPI1         (0xFFF88000)
+
+ /*
+  * nuc932 virtual address mapping.
+  * interrupt controller is the first thing we put in, to make
+  * the assembly code for the irq detection easier
+  */
+
+#define NUC93X_VA_IRQ          NUC93X_ADDR(0x00000000)
+#define NUC93X_SZ_IRQ          SZ_4K
+
+#define NUC93X_VA_GCR          NUC93X_ADDR(NUC93X_PA_IRQ)
+#define NUC93X_VA_CLKPWR       (NUC93X_VA_GCR+CLK_OFFSET)
+#define NUC93X_SZ_GCR          SZ_4K
+
+/* EBI management */
+
+#define NUC93X_VA_EBI          NUC93X_ADDR(NUC93X_PA_EBI)
+#define NUC93X_SZ_EBI          SZ_4K
+
+/* UARTs */
+
+#define NUC93X_VA_UART         NUC93X_ADDR(NUC93X_PA_UART)
+#define NUC93X_SZ_UART         SZ_4K
+
+/* Timers */
+
+#define NUC93X_VA_TIMER        NUC93X_ADDR(NUC93X_PA_TIMER)
+#define NUC93X_SZ_TIMER        SZ_4K
+
+/* GPIO ports */
+
+#define NUC93X_VA_GPIO         NUC93X_ADDR(NUC93X_PA_GPIO)
+#define NUC93X_SZ_GPIO         SZ_4K
+
+/* GDMA control */
+
+#define NUC93X_VA_GDMA         NUC93X_ADDR(NUC93X_PA_GDMA)
+#define NUC93X_SZ_GDMA         SZ_4K
+
+/* I2C hardware controller */
+
+#define NUC93X_VA_I2C          NUC93X_ADDR(NUC93X_PA_I2C)
+#define NUC93X_SZ_I2C          SZ_4K
+
+/* LCD controller*/
+
+#define NUC93X_VA_LCD          NUC93X_ADDR(NUC93X_PA_LCD)
+#define NUC93X_SZ_LCD          SZ_4K
+
+/* 2D controller*/
+
+#define NUC93X_VA_GE           NUC93X_ADDR(NUC93X_PA_GE)
+#define NUC93X_SZ_GE           SZ_4K
+
+/* ADC */
+
+#define NUC93X_VA_ADC          NUC93X_ADDR(NUC93X_PA_ADC)
+#define NUC93X_SZ_ADC          SZ_4K
+
+/* RTC */
+
+#define NUC93X_VA_RTC          NUC93X_ADDR(NUC93X_PA_RTC)
+#define NUC93X_SZ_RTC          SZ_4K
+
+/* Pulse Width Modulation(PWM) Registers */
+
+#define NUC93X_VA_PWM          NUC93X_ADDR(NUC93X_PA_PWM)
+#define NUC93X_SZ_PWM          SZ_4K
+
+/* Audio Controller controller */
+
+#define NUC93X_VA_ACTL         NUC93X_ADDR(NUC93X_PA_ACTL)
+#define NUC93X_SZ_ACTL         SZ_4K
+
+/* USB Device port */
+
+#define NUC93X_VA_USBDEV       NUC93X_ADDR(NUC93X_PA_USBDEV)
+#define NUC93X_SZ_USBDEV       SZ_4K
+
+/* USB host controller*/
+#define NUC93X_VA_USBHOST      NUC93X_ADDR(NUC93X_PA_USBHOST)
+#define NUC93X_SZ_USBHOST      SZ_4K
+
+#endif /* __ASM_ARCH_MAP_H */
diff --git a/arch/arm/mach-nuc93x/include/mach/memory.h b/arch/arm/mach-nuc93x/include/mach/memory.h
new file mode 100644 (file)
index 0000000..323ab0d
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * arch/arm/mach-nuc93x/include/mach/memory.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#ifndef __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+#define PHYS_OFFSET    UL(0x00000000)
+
+#endif
diff --git a/arch/arm/mach-nuc93x/include/mach/regs-clock.h b/arch/arm/mach-nuc93x/include/mach/regs-clock.h
new file mode 100644 (file)
index 0000000..5cb2954
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * arch/arm/mach-nuc93x/include/mach/regs-clock.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation;version 2 of the License.
+ *
+ */
+
+#ifndef __ASM_ARCH_REGS_CLOCK_H
+#define __ASM_ARCH_REGS_CLOCK_H
+
+/* Clock Control Registers  */
+#define CLK_BA         NUC93X_VA_CLKPWR
+#define REG_CLKEN      (CLK_BA + 0x00)
+#define REG_CLKSEL     (CLK_BA + 0x04)
+#define REG_CLKDIV     (CLK_BA + 0x08)
+#define REG_PLLCON0    (CLK_BA + 0x0C)
+#define REG_PLLCON1    (CLK_BA + 0x10)
+#define REG_PMCON      (CLK_BA + 0x14)
+#define REG_IRQWAKECON (CLK_BA + 0x18)
+#define REG_IRQWAKEFLAG        (CLK_BA + 0x1C)
+#define REG_IPSRST     (CLK_BA + 0x20)
+#define REG_CLKEN1     (CLK_BA + 0x24)
+#define REG_CLKDIV1    (CLK_BA + 0x28)
+
+/* Define PLL freq setting */
+#define PLL_DISABLE            0x12B63
+#define        PLL_66MHZ               0x2B63
+#define        PLL_100MHZ              0x4F64
+#define PLL_120MHZ             0x4F63
+#define        PLL_166MHZ              0x4124
+#define        PLL_200MHZ              0x4F24
+
+/* Define AHB:CPUFREQ ratio */
+#define        AHB_CPUCLK_1_1          0x00
+#define        AHB_CPUCLK_1_2          0x01
+#define        AHB_CPUCLK_1_4          0x02
+#define        AHB_CPUCLK_1_8          0x03
+
+/* Define APB:AHB ratio */
+#define APB_AHB_1_2            0x01
+#define APB_AHB_1_4            0x02
+#define APB_AHB_1_8            0x03
+
+/* Define clock skew */
+#define DEFAULTSKEW            0x48
+
+#endif /*  __ASM_ARCH_REGS_CLOCK_H */
diff --git a/arch/arm/mach-nuc93x/include/mach/regs-ebi.h b/arch/arm/mach-nuc93x/include/mach/regs-ebi.h
new file mode 100644 (file)
index 0000000..3c72550
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * arch/arm/mach-nuc93x/include/mach/regs-ebi.h
+ *
+ * Copyright (c) 2009 Nuvoton technology corporation.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation;version 2 of the License.
+ *
+ */
+
+#ifndef __ASM_ARCH_REGS_EBI_H
+#define __ASM_ARCH_REGS_EBI_H
+
+/* EBI Control Registers */
+
+#define EBI_BA         NUC93X_VA_EBI
+#define REG_EBICON     (EBI_BA + 0x00)
+#define REG_ROMCON     (EBI_BA + 0x04)
+#define REG_SDCONF0    (EBI_BA + 0x08)
+#define REG_SDCONF1    (EBI_BA + 0x0C)
+#define REG_SDTIME0    (EBI_BA + 0x10)
+#define REG_SDTIME1    (EBI_BA + 0x14)
+#define REG_EXT0CON    (EBI_BA + 0x18)
+#define REG_EXT1CON    (EBI_BA + 0x1C)
+#define REG_EXT2CON    (EBI_BA + 0x20)
+#define REG_EXT3CON    (EBI_BA + 0x24)
+#define REG_EXT4CON    (EBI_BA + 0x28)
+#define REG_CKSKEW     (EBI_BA + 0x2C)
+
+#endif /*  __ASM_ARCH_REGS_EBI_H */
diff --git a/arch/arm/mach-nuc93x/include/mach/regs-irq.h b/arch/arm/mach-nuc93x/include/mach/regs-irq.h
new file mode 100644 (file)
index 0000000..2302159
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * arch/arm/mach-nuc93x/include/mach/regs-irq.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#ifndef ___ASM_ARCH_REGS_IRQ_H
+#define ___ASM_ARCH_REGS_IRQ_H
+
+/* Advance Interrupt Controller (AIC) Registers */
+
+#define AIC_BA                 NUC93X_VA_IRQ
+
+#define REG_AIC_IRQSC          (AIC_BA+0x80)
+#define REG_AIC_GEN            (AIC_BA+0x84)
+#define REG_AIC_GASR           (AIC_BA+0x88)
+#define REG_AIC_GSCR           (AIC_BA+0x8C)
+#define REG_AIC_IRSR           (AIC_BA+0x100)
+#define REG_AIC_IASR           (AIC_BA+0x104)
+#define REG_AIC_ISR            (AIC_BA+0x108)
+#define REG_AIC_IPER           (AIC_BA+0x10C)
+#define REG_AIC_ISNR           (AIC_BA+0x110)
+#define REG_AIC_IMR            (AIC_BA+0x114)
+#define REG_AIC_OISR           (AIC_BA+0x118)
+#define REG_AIC_MECR           (AIC_BA+0x120)
+#define REG_AIC_MDCR           (AIC_BA+0x124)
+#define REG_AIC_SSCR           (AIC_BA+0x128)
+#define REG_AIC_SCCR           (AIC_BA+0x12C)
+#define REG_AIC_EOSCR          (AIC_BA+0x130)
+#define AIC_IPER               (0x10C)
+#define AIC_ISNR               (0x110)
+
+#endif /* ___ASM_ARCH_REGS_IRQ_H */
diff --git a/arch/arm/mach-nuc93x/include/mach/regs-serial.h b/arch/arm/mach-nuc93x/include/mach/regs-serial.h
new file mode 100644 (file)
index 0000000..767a047
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * arch/arm/mach-nuc93x/include/mach/regs-serial.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#ifndef __ASM_ARM_REGS_SERIAL_H
+#define __ASM_ARM_REGS_SERIAL_H
+
+#define UART0_BA       NUC93X_VA_UART
+#define UART1_BA       (NUC93X_VA_UART+0x100)
+
+#define UART0_PA       NUC93X_PA_UART
+#define UART1_PA       (NUC93X_PA_UART+0x100)
+
+
+#ifndef __ASSEMBLY__
+
+struct nuc93x_uart_clksrc {
+       const char      *name;
+       unsigned int    divisor;
+       unsigned int    min_baud;
+       unsigned int    max_baud;
+};
+
+struct nuc93x_uartcfg {
+       unsigned char   hwport;
+       unsigned char   unused;
+       unsigned short  flags;
+       unsigned long   uart_flags;
+
+       unsigned long   ucon;
+       unsigned long   ulcon;
+       unsigned long   ufcon;
+
+       struct nuc93x_uart_clksrc *clocks;
+       unsigned int    clocks_size;
+};
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_ARM_REGS_SERIAL_H */
+
diff --git a/arch/arm/mach-nuc93x/include/mach/regs-timer.h b/arch/arm/mach-nuc93x/include/mach/regs-timer.h
new file mode 100644 (file)
index 0000000..394be96
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * arch/arm/mach-nuc93x/include/mach/regs-timer.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#ifndef __ASM_ARCH_REGS_TIMER_H
+#define __ASM_ARCH_REGS_TIMER_H
+
+/* Timer Registers */
+
+#define TMR_BA                 NUC93X_VA_TIMER
+#define REG_TCSR0              (TMR_BA+0x00)
+#define REG_TICR0              (TMR_BA+0x08)
+#define REG_TDR0               (TMR_BA+0x10)
+#define REG_TISR               (TMR_BA+0x18)
+#define REG_WTCR               (TMR_BA+0x1C)
+
+#endif /*  __ASM_ARCH_REGS_TIMER_H */
diff --git a/arch/arm/mach-nuc93x/include/mach/system.h b/arch/arm/mach-nuc93x/include/mach/system.h
new file mode 100644 (file)
index 0000000..d26bd9a
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * arch/arm/machnuc93x/include/mach/system.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * Based on arch/arm/mach-s3c2410/include/mach/system.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <asm/proc-fns.h>
+
+static void arch_idle(void)
+{
+}
+
+static void arch_reset(char mode, const char *cmd)
+{
+       cpu_reset(0);
+}
+
diff --git a/arch/arm/mach-nuc93x/include/mach/timex.h b/arch/arm/mach-nuc93x/include/mach/timex.h
new file mode 100644 (file)
index 0000000..0c719cc
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * arch/arm/mach-nuc93x/include/mach/timex.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * Based on arch/arm/mach-s3c2410/include/mach/timex.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#ifndef __ASM_ARCH_TIMEX_H
+#define __ASM_ARCH_TIMEX_H
+
+/* CLOCK_TICK_RATE Now, I don't use it. */
+
+#define CLOCK_TICK_RATE 27000000
+
+#endif /* __ASM_ARCH_TIMEX_H */
diff --git a/arch/arm/mach-nuc93x/include/mach/uncompress.h b/arch/arm/mach-nuc93x/include/mach/uncompress.h
new file mode 100644 (file)
index 0000000..73082cd
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * arch/arm/mach-nuc93x/include/mach/uncompress.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * Based on arch/arm/mach-s3c2410/include/mach/uncompress.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#ifndef __ASM_ARCH_UNCOMPRESS_H
+#define __ASM_ARCH_UNCOMPRESS_H
+
+/* Defines for UART registers */
+
+#include <mach/regs-serial.h>
+#include <mach/map.h>
+#include <linux/serial_reg.h>
+
+#define arch_decomp_wdog()
+
+#define TX_DONE        (UART_LSR_TEMT | UART_LSR_THRE)
+static u32 * uart_base = (u32 *)UART0_PA;
+
+static void putc(int ch)
+{
+       /* Check THRE and TEMT bits before we transmit the character.
+        */
+       while ((uart_base[UART_LSR] & TX_DONE) != TX_DONE)
+               barrier();
+
+       *uart_base = ch;
+}
+
+static inline void flush(void)
+{
+}
+
+static void arch_decomp_setup(void)
+{
+}
+
+#endif/* __ASM_NUC93X_UNCOMPRESS_H */
diff --git a/arch/arm/mach-nuc93x/include/mach/vmalloc.h b/arch/arm/mach-nuc93x/include/mach/vmalloc.h
new file mode 100644 (file)
index 0000000..98a21b8
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * arch/arm/mach-nuc93x/include/mach/vmalloc.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * Based on arch/arm/mach-s3c2410/include/mach/vmalloc.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#ifndef __ASM_ARCH_VMALLOC_H
+#define __ASM_ARCH_VMALLOC_H
+
+#define VMALLOC_END      (0xE0000000)
+
+#endif /* __ASM_ARCH_VMALLOC_H */
diff --git a/arch/arm/mach-nuc93x/irq.c b/arch/arm/mach-nuc93x/irq.c
new file mode 100644 (file)
index 0000000..a7a88ea
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * linux/arch/arm/mach-nuc93x/irq.c
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation;version 2 of the License.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/ptrace.h>
+#include <linux/sysdev.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/regs-irq.h>
+
+static void nuc93x_irq_mask(unsigned int irq)
+{
+       __raw_writel(1 << irq, REG_AIC_MDCR);
+}
+
+/*
+ * By the w90p910 spec,any irq,only write 1
+ * to REG_AIC_EOSCR for ACK
+ */
+
+static void nuc93x_irq_ack(unsigned int irq)
+{
+       __raw_writel(0x01, REG_AIC_EOSCR);
+}
+
+static void nuc93x_irq_unmask(unsigned int irq)
+{
+       __raw_writel(1 << irq, REG_AIC_MECR);
+
+}
+
+static struct irq_chip nuc93x_irq_chip = {
+       .ack       = nuc93x_irq_ack,
+       .mask      = nuc93x_irq_mask,
+       .unmask    = nuc93x_irq_unmask,
+};
+
+void __init nuc93x_init_irq(void)
+{
+       int irqno;
+
+       __raw_writel(0xFFFFFFFE, REG_AIC_MDCR);
+
+       for (irqno = IRQ_WDT; irqno <= NR_IRQS; irqno++) {
+               set_irq_chip(irqno, &nuc93x_irq_chip);
+               set_irq_handler(irqno, handle_level_irq);
+               set_irq_flags(irqno, IRQF_VALID);
+       }
+}
diff --git a/arch/arm/mach-nuc93x/mach-nuc932evb.c b/arch/arm/mach-nuc93x/mach-nuc932evb.c
new file mode 100644 (file)
index 0000000..9f79266
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * linux/arch/arm/mach-w90x900/mach-nuc910evb.c
+ *
+ * Based on mach-s3c2410/mach-smdk2410.c by Jonas Dietsche
+ *
+ * Copyright (C) 2008 Nuvoton technology corporation.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation;version 2 of the License.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach-types.h>
+#include <mach/map.h>
+
+#include "nuc932.h"
+
+static void __init nuc932evb_map_io(void)
+{
+       nuc932_map_io();
+       nuc932_init_clocks();
+       nuc932_init_uartclk();
+}
+
+static void __init nuc932evb_init(void)
+{
+       nuc932_board_init();
+}
+
+MACHINE_START(NUC932EVB, "NUC932EVB")
+       /* Maintainer: Wan ZongShun */
+       .phys_io        = NUC93X_PA_UART,
+       .io_pg_offst    = (((u32)NUC93X_VA_UART) >> 18) & 0xfffc,
+       .boot_params    = 0,
+       .map_io         = nuc932evb_map_io,
+       .init_irq       = nuc93x_init_irq,
+       .init_machine   = nuc932evb_init,
+       .timer          = &nuc93x_timer,
+MACHINE_END
diff --git a/arch/arm/mach-nuc93x/nuc932.c b/arch/arm/mach-nuc93x/nuc932.c
new file mode 100644 (file)
index 0000000..3966ead
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * linux/arch/arm/mach-nuc93x/nuc932.c
+ *
+ * Copyright (c) 2009 Nuvoton corporation.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * NUC932 cpu support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation;version 2 of the License.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#include <asm/mach/map.h>
+#include <mach/hardware.h>
+
+#include "cpu.h"
+#include "clock.h"
+
+/* define specific CPU platform device */
+
+static struct platform_device *nuc932_dev[] __initdata = {
+};
+
+/* define specific CPU platform io map */
+
+static struct map_desc nuc932evb_iodesc[] __initdata = {
+};
+
+/*Init NUC932 evb io*/
+
+void __init nuc932_map_io(void)
+{
+       nuc93x_map_io(nuc932evb_iodesc, ARRAY_SIZE(nuc932evb_iodesc));
+}
+
+/*Init NUC932 clock*/
+
+void __init nuc932_init_clocks(void)
+{
+       nuc93x_init_clocks();
+}
+
+/*enable NUC932 uart clock*/
+
+void __init nuc932_init_uartclk(void)
+{
+       struct clk *ck_uart = clk_get(NULL, "uart");
+       BUG_ON(IS_ERR(ck_uart));
+
+       clk_enable(ck_uart);
+}
+
+/*Init NUC932 board info*/
+
+void __init nuc932_board_init(void)
+{
+       nuc93x_board_init(nuc932_dev, ARRAY_SIZE(nuc932_dev));
+}
diff --git a/arch/arm/mach-nuc93x/nuc932.h b/arch/arm/mach-nuc93x/nuc932.h
new file mode 100644 (file)
index 0000000..9a66edd
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * arch/arm/mach-nuc93x/nuc932.h
+ *
+ * Copyright (c) 2008 Nuvoton corporation
+ *
+ * Header file for NUC93x CPU support
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+struct map_desc;
+struct sys_timer;
+
+/* core initialisation functions */
+
+extern void nuc93x_init_irq(void);
+extern struct sys_timer nuc93x_timer;
+
+/* extern file from nuc932.c */
+
+extern void nuc932_board_init(void);
+extern void nuc932_init_clocks(void);
+extern void nuc932_map_io(void);
+extern void nuc932_init_uartclk(void);
diff --git a/arch/arm/mach-nuc93x/time.c b/arch/arm/mach-nuc93x/time.c
new file mode 100644 (file)
index 0000000..2f90f9d
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * linux/arch/arm/mach-nuc93x/time.c
+ *
+ * Copyright (c) 2009 Nuvoton technology corporation.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/leds.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/time.h>
+
+#include <mach/system.h>
+#include <mach/map.h>
+#include <mach/regs-timer.h>
+
+#define RESETINT       0x01
+#define PERIOD         (0x01 << 27)
+#define ONESHOT                (0x00 << 27)
+#define COUNTEN                (0x01 << 30)
+#define INTEN          (0x01 << 29)
+
+#define TICKS_PER_SEC  100
+#define PRESCALE       0x63 /* Divider = prescale + 1 */
+
+unsigned int timer0_load;
+
+static unsigned long nuc93x_gettimeoffset(void)
+{
+       return 0;
+}
+
+/*IRQ handler for the timer*/
+
+static irqreturn_t nuc93x_timer_interrupt(int irq, void *dev_id)
+{
+       timer_tick();
+       __raw_writel(0x01, REG_TISR); /* clear TIF0 */
+       return IRQ_HANDLED;
+}
+
+static struct irqaction nuc93x_timer_irq = {
+       .name           = "nuc93x Timer Tick",
+       .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+       .handler        = nuc93x_timer_interrupt,
+};
+
+/*Set up timer reg.*/
+
+static void nuc93x_timer_setup(void)
+{
+       struct clk *ck_ext = clk_get(NULL, "ext");
+       struct clk *ck_timer = clk_get(NULL, "timer");
+       unsigned int rate, val = 0;
+
+       BUG_ON(IS_ERR(ck_ext) || IS_ERR(ck_timer));
+
+       clk_enable(ck_timer);
+       rate = clk_get_rate(ck_ext);
+       clk_put(ck_ext);
+       rate = rate / (PRESCALE + 0x01);
+
+        /* set a known state */
+       __raw_writel(0x00, REG_TCSR0);
+       __raw_writel(RESETINT, REG_TISR);
+
+       timer0_load = (rate / TICKS_PER_SEC);
+       __raw_writel(timer0_load, REG_TICR0);
+
+       val |= (PERIOD | COUNTEN | INTEN | PRESCALE);;
+       __raw_writel(val, REG_TCSR0);
+
+}
+
+static void __init nuc93x_timer_init(void)
+{
+       nuc93x_timer_setup();
+       setup_irq(IRQ_TIMER0, &nuc93x_timer_irq);
+}
+
+struct sys_timer nuc93x_timer = {
+       .init           = nuc93x_timer_init,
+       .offset         = nuc93x_gettimeoffset,
+       .resume         = nuc93x_timer_setup
+};
index aedb746fc33c950c0e4d5579681f52018c86675c..8c74cab2fa8b92b809bfbba4bd3ddad66a8d8b35 100644 (file)
@@ -11,7 +11,7 @@
  *
 */
 
-               .macro  addruart,rx
+               .macro  addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                 @ MMU enabled?
                moveq   \rx, #0xff000000        @ physical base address
index 0c6be6b4a7e2b6f3fc40ba803c7f574289ebf0a8..8ba8fb5b2514cdb09343f98ea45676aff0b8fab8 100644 (file)
@@ -28,6 +28,7 @@
 #include <plat/control.h>
 #include <plat/timer-gp.h>
 #include <asm/hardware/gic.h>
+#include <asm/hardware/cache-l2x0.h>
 
 static struct platform_device sdp4430_lcd_device = {
        .name           = "sdp4430_lcd",
@@ -50,6 +51,59 @@ static struct omap_board_config_kernel sdp4430_config[] __initdata = {
        { OMAP_TAG_LCD,         &sdp4430_lcd_config },
 };
 
+#ifdef CONFIG_CACHE_L2X0
+noinline void omap_smc1(u32 fn, u32 arg)
+{
+       register u32 r12 asm("r12") = fn;
+       register u32 r0 asm("r0") = arg;
+
+       /* This is common routine cache secure monitor API used to
+        * modify the PL310 secure registers.
+        * r0 contains the value to be modified and "r12" contains
+        * the monitor API number. It uses few CPU registers
+        * internally and hence they need be backed up including
+        * link register "lr".
+        * Explicitly save r11 and r12 the compiler generated code
+        * won't save it.
+        */
+       asm volatile(
+               "stmfd r13!, {r11,r12}\n"
+               "dsb\n"
+               "smc\n"
+               "ldmfd r13!, {r11,r12}\n"
+               : "+r" (r0), "+r" (r12)
+               :
+               : "r4", "r5", "r10", "lr", "cc");
+}
+EXPORT_SYMBOL(omap_smc1);
+
+static int __init omap_l2_cache_init(void)
+{
+       void __iomem *l2cache_base;
+
+       /* To avoid code running on other OMAPs in
+        * multi-omap builds
+        */
+       if (!cpu_is_omap44xx())
+               return -ENODEV;
+
+       /* Static mapping, never released */
+       l2cache_base = ioremap(OMAP44XX_L2CACHE_BASE, SZ_4K);
+       BUG_ON(!l2cache_base);
+
+       /* Enable PL310 L2 Cache controller */
+       omap_smc1(0x102, 0x1);
+
+       /* 32KB way size, 16-way associativity,
+       * parity disabled
+       */
+       l2x0_init(l2cache_base, 0x0e050000, 0xc0000fff);
+
+       return 0;
+}
+early_initcall(omap_l2_cache_init);
+#endif
+
 static void __init gic_init_irq(void)
 {
        void __iomem *base;
index e9f255df9163b827c6a9fc300b0b65345e79d329..86979d7bd8714d8715586e254163c2345af72394 100644 (file)
@@ -11,7 +11,7 @@
  *
 */
 
-               .macro  addruart,rx
+               .macro  addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                 @ MMU enabled?
 #ifdef  CONFIG_ARCH_OMAP2
index c7f808bfe272fa1caa477182e91cb566ff9b2c4a..91e0e39bb23f1602a98068234c28268f262e455c 100644 (file)
@@ -10,7 +10,7 @@
 
 #include <mach/orion5x.h>
 
-       .macro  addruart,rx
+       .macro  addruart, rx, tmp
        mrc     p15, 0, \rx, c1, c0
        tst     \rx, #1                                 @ MMU enabled?
        ldreq   \rx, =ORION5X_REGS_PHYS_BASE
index 7147a297e97f4c2e11e8d5a1fd03dc3608ee34d9..06b50aeff7b90fb78d4320685976f383c3e315e3 100644 (file)
@@ -2,4 +2,4 @@
  * arch/arm/mach-orion5x/include/mach/vmalloc.h
  */
 
-#define VMALLOC_END       0xfd800000
+#define VMALLOC_END       0xfd800000UL
index 898c0e88acbc30ade69d561e5493e936e23bebdb..9d1975fa4d9f2c2e71e3782c7716bd66c5c67dff 100644 (file)
@@ -22,8 +22,9 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 
-#include <mach/hardware.h>
+#include <asm/clkdev.h>
 
+#include <mach/hardware.h>
 #include <mach/clock.h>
 #include "clock.h"
 
@@ -56,18 +57,19 @@ static void propagate_rate(struct clk *clk)
        }
 }
 
-static inline void clk_reg_disable(struct clk *clk)
+static void clk_reg_disable(struct clk *clk)
 {
        if (clk->enable_reg)
                __raw_writel(__raw_readl(clk->enable_reg) &
                             ~(1 << clk->enable_shift), clk->enable_reg);
 }
 
-static inline void clk_reg_enable(struct clk *clk)
+static int clk_reg_enable(struct clk *clk)
 {
        if (clk->enable_reg)
                __raw_writel(__raw_readl(clk->enable_reg) |
                             (1 << clk->enable_shift), clk->enable_reg);
+       return 0;
 }
 
 static inline void clk_reg_disable1(struct clk *clk)
@@ -636,31 +638,34 @@ static struct clk flash_ck = {
 static struct clk i2c0_ck = {
        .name = "i2c0_ck",
        .parent = &per_ck,
-       .flags = NEEDS_INITIALIZATION,
-       .round_rate = &on_off_round_rate,
-       .set_rate = &on_off_set_rate,
+       .flags = NEEDS_INITIALIZATION | FIXED_RATE,
        .enable_shift = 0,
        .enable_reg = I2CCLKCTRL_REG,
+       .rate = 13000000,
+       .enable = clk_reg_enable,
+       .disable = clk_reg_disable,
 };
 
 static struct clk i2c1_ck = {
        .name = "i2c1_ck",
        .parent = &per_ck,
-       .flags = NEEDS_INITIALIZATION,
-       .round_rate = &on_off_round_rate,
-       .set_rate = &on_off_set_rate,
+       .flags = NEEDS_INITIALIZATION | FIXED_RATE,
        .enable_shift = 1,
        .enable_reg = I2CCLKCTRL_REG,
+       .rate = 13000000,
+       .enable = clk_reg_enable,
+       .disable = clk_reg_disable,
 };
 
 static struct clk i2c2_ck = {
        .name = "i2c2_ck",
        .parent = &per_ck,
-       .flags = NEEDS_INITIALIZATION,
-       .round_rate = &on_off_round_rate,
-       .set_rate = &on_off_set_rate,
+       .flags = NEEDS_INITIALIZATION | FIXED_RATE,
        .enable_shift = 2,
        .enable_reg = USB_OTG_CLKCTRL_REG,
+       .rate = 13000000,
+       .enable = clk_reg_enable,
+       .disable = clk_reg_disable,
 };
 
 static struct clk spi0_ck = {
@@ -738,16 +743,16 @@ static struct clk wdt_ck = {
        .name = "wdt_ck",
        .parent = &per_ck,
        .flags = NEEDS_INITIALIZATION,
-       .round_rate = &on_off_round_rate,
-       .set_rate = &on_off_set_rate,
        .enable_shift = 0,
        .enable_reg = TIMCLKCTRL_REG,
+       .enable = clk_reg_enable,
+       .disable = clk_reg_disable,
 };
 
 /* These clocks are visible outside this module
  * and can be initialized
  */
-static struct clk *onchip_clks[] = {
+static struct clk *onchip_clks[] __initdata = {
        &ck_13MHz,
        &ck_pll1,
        &ck_pll4,
@@ -777,49 +782,74 @@ static struct clk *onchip_clks[] = {
        &wdt_ck,
 };
 
-static int local_clk_enable(struct clk *clk)
-{
-       int ret = 0;
-
-       if (!(clk->flags & FIXED_RATE) && !clk->rate && clk->set_rate
-           && clk->user_rate)
-               ret = clk->set_rate(clk, clk->user_rate);
-       return ret;
-}
+static struct clk_lookup onchip_clkreg[] = {
+       { .clk = &ck_13MHz,     .con_id = "ck_13MHz"    },
+       { .clk = &ck_pll1,      .con_id = "ck_pll1"     },
+       { .clk = &ck_pll4,      .con_id = "ck_pll4"     },
+       { .clk = &ck_pll5,      .con_id = "ck_pll5"     },
+       { .clk = &ck_pll3,      .con_id = "ck_pll3"     },
+       { .clk = &vfp9_ck,      .con_id = "vfp9_ck"     },
+       { .clk = &m2hclk_ck,    .con_id = "m2hclk_ck"   },
+       { .clk = &hclk_ck,      .con_id = "hclk_ck"     },
+       { .clk = &dma_ck,       .con_id = "dma_ck"      },
+       { .clk = &flash_ck,     .con_id = "flash_ck"    },
+       { .clk = &dum_ck,       .con_id = "dum_ck"      },
+       { .clk = &keyscan_ck,   .con_id = "keyscan_ck"  },
+       { .clk = &pwm1_ck,      .con_id = "pwm1_ck"     },
+       { .clk = &pwm2_ck,      .con_id = "pwm2_ck"     },
+       { .clk = &jpeg_ck,      .con_id = "jpeg_ck"     },
+       { .clk = &ms_ck,        .con_id = "ms_ck"       },
+       { .clk = &touch_ck,     .con_id = "touch_ck"    },
+       { .clk = &i2c0_ck,      .dev_id = "pnx-i2c.0"   },
+       { .clk = &i2c1_ck,      .dev_id = "pnx-i2c.1"   },
+       { .clk = &i2c2_ck,      .dev_id = "pnx-i2c.2"   },
+       { .clk = &spi0_ck,      .con_id = "spi0_ck"     },
+       { .clk = &spi1_ck,      .con_id = "spi1_ck"     },
+       { .clk = &uart3_ck,     .con_id = "uart3_ck"    },
+       { .clk = &uart4_ck,     .con_id = "uart4_ck"    },
+       { .clk = &uart5_ck,     .con_id = "uart5_ck"    },
+       { .clk = &uart6_ck,     .con_id = "uart6_ck"    },
+       { .clk = &wdt_ck,       .dev_id = "pnx4008-watchdog" },
+};
 
 static void local_clk_disable(struct clk *clk)
 {
-       if (!(clk->flags & FIXED_RATE) && clk->rate && clk->set_rate)
-               clk->set_rate(clk, 0);
-}
+       if (WARN_ON(clk->usecount == 0))
+               return;
 
-static void local_clk_unuse(struct clk *clk)
-{
-       if (clk->usecount > 0 && !(--clk->usecount)) {
-               local_clk_disable(clk);
+       if (!(--clk->usecount)) {
+               if (clk->disable)
+                       clk->disable(clk);
+               else if (!(clk->flags & FIXED_RATE) && clk->rate && clk->set_rate)
+                       clk->set_rate(clk, 0);
                if (clk->parent)
-                       local_clk_unuse(clk->parent);
+                       local_clk_disable(clk->parent);
        }
 }
 
-static int local_clk_use(struct clk *clk)
+static int local_clk_enable(struct clk *clk)
 {
        int ret = 0;
-       if (clk->usecount++ == 0) {
-               if (clk->parent)
-                       ret = local_clk_use(clk->parent);
 
-               if (ret != 0) {
-                       clk->usecount--;
-                       goto out;
+       if (clk->usecount == 0) {
+               if (clk->parent) {
+                       ret = local_clk_enable(clk->parent);
+                       if (ret != 0)
+                               goto out;
                }
 
-               ret = local_clk_enable(clk);
+               if (clk->enable)
+                       ret = clk->enable(clk);
+               else if (!(clk->flags & FIXED_RATE) && !clk->rate && clk->set_rate
+                           && clk->user_rate)
+                       ret = clk->set_rate(clk, clk->user_rate);
 
                if (ret != 0 && clk->parent) {
-                       local_clk_unuse(clk->parent);
-                       clk->usecount--;
+                       local_clk_disable(clk->parent);
+                       goto out;
                }
+
+               clk->usecount++;
        }
 out:
        return ret;
@@ -866,35 +896,6 @@ out:
 
 EXPORT_SYMBOL(clk_set_rate);
 
-struct clk *clk_get(struct device *dev, const char *id)
-{
-       struct clk *clk = ERR_PTR(-ENOENT);
-       struct clk **clkp;
-
-       clock_lock();
-       for (clkp = onchip_clks; clkp < onchip_clks + ARRAY_SIZE(onchip_clks);
-            clkp++) {
-               if (strcmp(id, (*clkp)->name) == 0
-                   && try_module_get((*clkp)->owner)) {
-                       clk = (*clkp);
-                       break;
-               }
-       }
-       clock_unlock();
-
-       return clk;
-}
-EXPORT_SYMBOL(clk_get);
-
-void clk_put(struct clk *clk)
-{
-       clock_lock();
-       if (clk && !IS_ERR(clk))
-               module_put(clk->owner);
-       clock_unlock();
-}
-EXPORT_SYMBOL(clk_put);
-
 unsigned long clk_get_rate(struct clk *clk)
 {
        unsigned long ret;
@@ -907,10 +908,10 @@ EXPORT_SYMBOL(clk_get_rate);
 
 int clk_enable(struct clk *clk)
 {
-       int ret = 0;
+       int ret;
 
        clock_lock();
-       ret = local_clk_use(clk);
+       ret = local_clk_enable(clk);
        clock_unlock();
        return ret;
 }
@@ -920,7 +921,7 @@ EXPORT_SYMBOL(clk_enable);
 void clk_disable(struct clk *clk)
 {
        clock_lock();
-       local_clk_unuse(clk);
+       local_clk_disable(clk);
        clock_unlock();
 }
 
@@ -967,18 +968,24 @@ static int __init clk_init(void)
 
        for (clkp = onchip_clks; clkp < onchip_clks + ARRAY_SIZE(onchip_clks);
             clkp++) {
-               if (((*clkp)->flags & NEEDS_INITIALIZATION)
-                   && ((*clkp)->set_rate)) {
-                       (*clkp)->user_rate = (*clkp)->rate;
-                       local_set_rate((*clkp), (*clkp)->user_rate);
-                       if ((*clkp)->set_parent)
-                               (*clkp)->set_parent((*clkp), (*clkp)->parent);
+               struct clk *clk = *clkp;
+               if (clk->flags & NEEDS_INITIALIZATION) {
+                       if (clk->set_rate) {
+                               clk->user_rate = clk->rate;
+                               local_set_rate(clk, clk->user_rate);
+                               if (clk->set_parent)
+                                       clk->set_parent(clk, clk->parent);
+                       }
+                       if (clk->enable && clk->usecount)
+                               clk->enable(clk);
+                       if (clk->disable && !clk->usecount)
+                               clk->disable(clk);
                }
                pr_debug("%s: clock %s, rate %ld\n",
-                       __func__, (*clkp)->name, (*clkp)->rate);
+                       __func__, clk->name, clk->rate);
        }
 
-       local_clk_use(&ck_pll4);
+       local_clk_enable(&ck_pll4);
 
        /* if ck_13MHz is not used, disable it. */
        if (ck_13MHz.usecount == 0)
@@ -987,6 +994,8 @@ static int __init clk_init(void)
        /* Disable autoclocking */
        __raw_writeb(0xff, AUTOCLK_CTRL);
 
+       clkdev_add_table(onchip_clkreg, ARRAY_SIZE(onchip_clkreg));
+
        return 0;
 }
 
index cd58f372cfd0aa68eae44d810a7a054efd0057ed..39720d6c0d014e370d5804918e263c05a11a6946 100644 (file)
@@ -14,8 +14,6 @@
 #define __ARCH_ARM_PNX4008_CLOCK_H__
 
 struct clk {
-       struct list_head node;
-       struct module *owner;
        const char *name;
        struct clk *parent;
        struct clk *propagate_next;
@@ -29,9 +27,11 @@ struct clk {
        u8 enable_shift1;
        u32 enable_reg1;
        u32 parent_switch_reg;
-        u32(*round_rate) (struct clk *, u32);
+       u32(*round_rate) (struct clk *, u32);
        int (*set_rate) (struct clk *, u32);
        int (*set_parent) (struct clk * clk, struct clk * parent);
+       int (*enable)(struct clk *);
+       void (*disable)(struct clk *);
 };
 
 /* Flags */
index f3fea29c00d3b3072008bf52f2c224370f544357..8103f9644e2d0af099ccadb0b80b29440574119c 100644 (file)
 #include <mach/irqs.h>
 #include <mach/i2c.h>
 
-static int set_clock_run(struct platform_device *pdev)
-{
-       struct clk *clk;
-       char name[10];
-       int retval = 0;
-
-       snprintf(name, 10, "i2c%d_ck", pdev->id);
-       clk = clk_get(&pdev->dev, name);
-       if (!IS_ERR(clk)) {
-               clk_set_rate(clk, 1);
-               clk_put(clk);
-       } else
-               retval = -ENOENT;
-
-       return retval;
-}
-
-static int set_clock_stop(struct platform_device *pdev)
-{
-       struct clk *clk;
-       char name[10];
-       int retval = 0;
-
-       snprintf(name, 10, "i2c%d_ck", pdev->id);
-       clk = clk_get(&pdev->dev, name);
-       if (!IS_ERR(clk)) {
-               clk_set_rate(clk, 0);
-               clk_put(clk);
-       } else
-               retval = -ENOENT;
-
-       return retval;
-}
-
-static int i2c_pnx_suspend(struct platform_device *pdev, pm_message_t state)
-{
-       int retval = 0;
-#ifdef CONFIG_PM
-       retval = set_clock_run(pdev);
-#endif
-       return retval;
-}
-
-static int i2c_pnx_resume(struct platform_device *pdev)
-{
-       int retval = 0;
-#ifdef CONFIG_PM
-       retval = set_clock_run(pdev);
-#endif
-       return retval;
-}
-
-static u32 calculate_input_freq(struct platform_device *pdev)
-{
-       return HCLK_MHZ;
-}
-
-
-static struct i2c_pnx_algo_data pnx_algo_data0 = {
+static struct i2c_pnx_data i2c0_data = {
+       .name = I2C_CHIP_NAME "0",
        .base = PNX4008_I2C1_BASE,
        .irq = I2C_1_INT,
 };
 
-static struct i2c_pnx_algo_data pnx_algo_data1 = {
+static struct i2c_pnx_data i2c1_data = {
+       .name = I2C_CHIP_NAME "1",
        .base = PNX4008_I2C2_BASE,
        .irq = I2C_2_INT,
 };
 
-static struct i2c_pnx_algo_data pnx_algo_data2 = {
+static struct i2c_pnx_data i2c2_data = {
+       .name = "USB-I2C",
        .base = (PNX4008_USB_CONFIG_BASE + 0x300),
        .irq = USB_I2C_INT,
 };
 
-static struct i2c_adapter pnx_adapter0 = {
-       .name = I2C_CHIP_NAME "0",
-       .algo_data = &pnx_algo_data0,
-};
-static struct i2c_adapter pnx_adapter1 = {
-       .name = I2C_CHIP_NAME "1",
-       .algo_data = &pnx_algo_data1,
-};
-
-static struct i2c_adapter pnx_adapter2 = {
-       .name = "USB-I2C",
-       .algo_data = &pnx_algo_data2,
-};
-
-static struct i2c_pnx_data i2c0_data = {
-       .suspend = i2c_pnx_suspend,
-       .resume = i2c_pnx_resume,
-       .calculate_input_freq = calculate_input_freq,
-       .set_clock_run = set_clock_run,
-       .set_clock_stop = set_clock_stop,
-       .adapter = &pnx_adapter0,
-};
-
-static struct i2c_pnx_data i2c1_data = {
-       .suspend = i2c_pnx_suspend,
-       .resume = i2c_pnx_resume,
-       .calculate_input_freq = calculate_input_freq,
-       .set_clock_run = set_clock_run,
-       .set_clock_stop = set_clock_stop,
-       .adapter = &pnx_adapter1,
-};
-
-static struct i2c_pnx_data i2c2_data = {
-       .suspend = i2c_pnx_suspend,
-       .resume = i2c_pnx_resume,
-       .calculate_input_freq = calculate_input_freq,
-       .set_clock_run = set_clock_run,
-       .set_clock_stop = set_clock_stop,
-       .adapter = &pnx_adapter2,
-};
-
 static struct platform_device i2c0_device = {
        .name = "pnx-i2c",
        .id = 0,
diff --git a/arch/arm/mach-pnx4008/include/mach/clkdev.h b/arch/arm/mach-pnx4008/include/mach/clkdev.h
new file mode 100644 (file)
index 0000000..04b37a8
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __ASM_MACH_CLKDEV_H
+#define __ASM_MACH_CLKDEV_H
+
+#define __clk_get(clk) ({ 1; })
+#define __clk_put(clk) do { } while (0)
+
+#endif
index 6d1407f319f8281fc780f34e64037e42cb5ea09c..6ca8bd30bf46f32dd0e55c9284b0962242596dff 100644 (file)
@@ -11,7 +11,7 @@
  *
 */
 
-               .macro  addruart,rx
+               .macro  addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                 @ MMU enabled?
                mov     \rx, #0x00090000
index 5ff0196c0f167dd8a72c9443b0353e926123ed83..b383c7de7ab44e811e8b85ae2cf0270a2a7edcf3 100644 (file)
 #ifndef __PNX4008_TIMEX_H
 #define __PNX4008_TIMEX_H
 
-#include <linux/io.h>
-#include <mach/hardware.h>
-
 #define CLOCK_TICK_RATE                1000000
 
-#define TICKS2USECS(x) (x)
-
-/* MilliSecond Timer - Chapter 21 Page 202 */
-
-#define MSTIM_INT     IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x0))
-#define MSTIM_CTRL    IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x4))
-#define MSTIM_COUNTER IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x8))
-#define MSTIM_MCTRL   IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x14))
-#define MSTIM_MATCH0  IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x18))
-#define MSTIM_MATCH1  IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x1c))
-
-/* High Speed Timer - Chpater 22, Page 205 */
-
-#define HSTIM_INT     IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x0))
-#define HSTIM_CTRL    IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x4))
-#define HSTIM_COUNTER IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x8))
-#define HSTIM_PMATCH  IO_ADDRESS((PNX4008_HSTIMER_BASE + 0xC))
-#define HSTIM_PCOUNT  IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x10))
-#define HSTIM_MCTRL   IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x14))
-#define HSTIM_MATCH0  IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x18))
-#define HSTIM_MATCH1  IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x1c))
-#define HSTIM_MATCH2  IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x20))
-#define HSTIM_CCR     IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x28))
-#define HSTIM_CR0     IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x2C))
-#define HSTIM_CR1     IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x30))
-
-/* IMPORTANT: both timers are UPCOUNTING */
-
-/* xSTIM_MCTRL bit definitions */
-#define MR0_INT        1
-#define RESET_COUNT0   (1<<1)
-#define STOP_COUNT0    (1<<2)
-#define MR1_INT        (1<<3)
-#define RESET_COUNT1   (1<<4)
-#define STOP_COUNT1    (1<<5)
-#define MR2_INT        (1<<6)
-#define RESET_COUNT2   (1<<7)
-#define STOP_COUNT2    (1<<8)
-
-/* xSTIM_CTRL bit definitions */
-#define COUNT_ENAB     1
-#define RESET_COUNT    (1<<1)
-#define DEBUG_EN       (1<<2)
-
-/* xSTIM_INT bit definitions */
-#define MATCH0_INT     1
-#define MATCH1_INT     (1<<1)
-#define MATCH2_INT     (1<<2)
-#define RTC_TICK0      (1<<4)
-#define RTC_TICK1      (1<<5)
-
 #endif
index b3d8d53e32ef8cd5733d0de3dac98bfffe9a9aef..1f0585329be48a3e651a365a9bc05b42c60b532b 100644 (file)
@@ -21,6 +21,8 @@
 #include <linux/io.h>
 
 #include <asm/cacheflush.h>
+
+#include <mach/hardware.h>
 #include <mach/pm.h>
 #include <mach/clock.h>
 
index fc0ba183fe1233dcd9165502281928e98b56775e..0c8aad4bb0dc877d0372f5ac7044597d41956f45 100644 (file)
@@ -30,6 +30,8 @@
 #include <asm/mach/time.h>
 #include <asm/errno.h>
 
+#include "time.h"
+
 /*! Note: all timers are UPCOUNTING */
 
 /*!
diff --git a/arch/arm/mach-pnx4008/time.h b/arch/arm/mach-pnx4008/time.h
new file mode 100644 (file)
index 0000000..75e88c5
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * arch/arm/mach-pnx4008/include/mach/timex.h
+ *
+ * PNX4008 timers header file
+ *
+ * Author: Dmitry Chigirev <source@mvista.com>
+ *
+ * 2005 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#ifndef PNX_TIME_H
+#define PNX_TIME_H
+
+#include <linux/io.h>
+#include <mach/hardware.h>
+
+#define TICKS2USECS(x) (x)
+
+/* MilliSecond Timer - Chapter 21 Page 202 */
+
+#define MSTIM_INT     IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x0))
+#define MSTIM_CTRL    IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x4))
+#define MSTIM_COUNTER IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x8))
+#define MSTIM_MCTRL   IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x14))
+#define MSTIM_MATCH0  IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x18))
+#define MSTIM_MATCH1  IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x1c))
+
+/* High Speed Timer - Chpater 22, Page 205 */
+
+#define HSTIM_INT     IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x0))
+#define HSTIM_CTRL    IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x4))
+#define HSTIM_COUNTER IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x8))
+#define HSTIM_PMATCH  IO_ADDRESS((PNX4008_HSTIMER_BASE + 0xC))
+#define HSTIM_PCOUNT  IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x10))
+#define HSTIM_MCTRL   IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x14))
+#define HSTIM_MATCH0  IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x18))
+#define HSTIM_MATCH1  IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x1c))
+#define HSTIM_MATCH2  IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x20))
+#define HSTIM_CCR     IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x28))
+#define HSTIM_CR0     IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x2C))
+#define HSTIM_CR1     IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x30))
+
+/* IMPORTANT: both timers are UPCOUNTING */
+
+/* xSTIM_MCTRL bit definitions */
+#define MR0_INT        1
+#define RESET_COUNT0   (1<<1)
+#define STOP_COUNT0    (1<<2)
+#define MR1_INT        (1<<3)
+#define RESET_COUNT1   (1<<4)
+#define STOP_COUNT1    (1<<5)
+#define MR2_INT        (1<<6)
+#define RESET_COUNT2   (1<<7)
+#define STOP_COUNT2    (1<<8)
+
+/* xSTIM_CTRL bit definitions */
+#define COUNT_ENAB     1
+#define RESET_COUNT    (1<<1)
+#define DEBUG_EN       (1<<2)
+
+/* xSTIM_INT bit definitions */
+#define MATCH0_INT     1
+#define MATCH1_INT     (1<<1)
+#define MATCH2_INT     (1<<2)
+#define RTC_TICK0      (1<<4)
+#define RTC_TICK1      (1<<5)
+
+#endif
index 49ae38292310c2b1058c433f7e2a16fbe378756f..abba0089a2ae0d6af3ca35a9bf961d9a5a65406e 100644 (file)
@@ -78,11 +78,3 @@ const struct clkops clk_cken_ops = {
        .enable         = clk_cken_enable,
        .disable        = clk_cken_disable,
 };
-
-void clks_register(struct clk_lookup *clks, size_t num)
-{
-       int i;
-
-       for (i = 0; i < num; i++)
-               clkdev_add(&clks[i]);
-}
index 978a3667e90dcd3548c2fc01fcbc82484c724686..d8488742b8075179fd4d66026d79730e00505a21 100644 (file)
@@ -67,7 +67,3 @@ extern void clk_pxa3xx_cken_enable(struct clk *);
 extern void clk_pxa3xx_cken_disable(struct clk *);
 #endif
 
-void clks_register(struct clk_lookup *clks, size_t num);
-int clk_add_alias(const char *alias, const char *alias_name, char *id,
-       struct device *dev);
-
index 91417f035069a0ce40efd7cc9c60d2542962bdd9..96ed13081639598335309b23b992751d27102ea5 100644 (file)
@@ -128,6 +128,6 @@ static struct clk_lookup eseries_clkregs[] = {
 
 void eseries_register_clks(void)
 {
-       clks_register(eseries_clkregs, ARRAY_SIZE(eseries_clkregs));
+       clkdev_add_table(eseries_clkregs, ARRAY_SIZE(eseries_clkregs));
 }
 
index 55d6a175ab19074a2851e57ceeb958dd5c08eda0..01cf81393fe2d5e25787ea87b375aa510e754f2c 100644 (file)
@@ -13,7 +13,7 @@
 
 #include "hardware.h"
 
-               .macro  addruart,rx
+               .macro  addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                 @ MMU enabled?
                moveq   \rx, #0x40000000                @ physical
index e90c5eeb81dde9b94304e2eae66ab7b10ea0337e..bfecfbf5f460a4fcfdeca64cd54d1cc6d644f635 100644 (file)
@@ -8,4 +8,4 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#define VMALLOC_END       (0xe8000000)
+#define VMALLOC_END       (0xe8000000UL)
index 2c1b0b70d01d0520b6b8facecd88c05884c319d6..0b9ad30bfd51cd659359dfbf2ded2412095033ad 100644 (file)
@@ -349,7 +349,7 @@ static int __init pxa25x_init(void)
 
                reset_status = RCSR;
 
-               clks_register(pxa25x_clkregs, ARRAY_SIZE(pxa25x_clkregs));
+               clkdev_add_table(pxa25x_clkregs, ARRAY_SIZE(pxa25x_clkregs));
 
                if ((ret = pxa_init_dma(IRQ_DMA, 16)))
                        return ret;
@@ -370,7 +370,7 @@ static int __init pxa25x_init(void)
 
        /* Only add HWUART for PXA255/26x; PXA210/250 do not have it. */
        if (cpu_is_pxa255())
-               clks_register(&pxa25x_hwuart_clkreg, 1);
+               clkdev_add(&pxa25x_hwuart_clkreg);
 
        return ret;
 }
index 6a0b73167e03b9bc4529c8e73060117f7fc02190..d783123e2d48e483917f88614dea852d74040504 100644 (file)
@@ -392,7 +392,7 @@ static int __init pxa27x_init(void)
 
                reset_status = RCSR;
 
-               clks_register(pxa27x_clkregs, ARRAY_SIZE(pxa27x_clkregs));
+               clkdev_add_table(pxa27x_clkregs, ARRAY_SIZE(pxa27x_clkregs));
 
                if ((ret = pxa_init_dma(IRQ_DMA, 32)))
                        return ret;
index f4af6e2bef892700b273db56e1b13605a1c22d56..40bb16501d8601789875c03bbef88dd87519c925 100644 (file)
@@ -102,12 +102,12 @@ static int __init pxa300_init(void)
        if (cpu_is_pxa300() || cpu_is_pxa310()) {
                mfp_init_base(io_p2v(MFPR_BASE));
                mfp_init_addr(pxa300_mfp_addr_map);
-               clks_register(ARRAY_AND_SIZE(common_clkregs));
+               clkdev_add_table(ARRAY_AND_SIZE(common_clkregs));
        }
 
        if (cpu_is_pxa310()) {
                mfp_init_addr(pxa310_mfp_addr_map);
-               clks_register(ARRAY_AND_SIZE(pxa310_clkregs));
+               clkdev_add_table(ARRAY_AND_SIZE(pxa310_clkregs));
        }
 
        return 0;
index c7373e74a109dffe6ad923e18c7c7ef951a121e4..8d614ecd8e998d3d663187656dd108ca29405e62 100644 (file)
@@ -90,7 +90,7 @@ static int __init pxa320_init(void)
        if (cpu_is_pxa320()) {
                mfp_init_base(io_p2v(MFPR_BASE));
                mfp_init_addr(pxa320_mfp_addr_map);
-               clks_register(ARRAY_AND_SIZE(pxa320_clkregs));
+               clkdev_add_table(ARRAY_AND_SIZE(pxa320_clkregs));
        }
 
        return 0;
index fcb0721f466947f221c447f235846841204f8bf8..4d7c03e725042e4d735c7b0055df65ce26214bda 100644 (file)
@@ -634,7 +634,7 @@ static int __init pxa3xx_init(void)
                 */
                ASCR &= ~(ASCR_RDH | ASCR_D1S | ASCR_D2S | ASCR_D3S);
 
-               clks_register(pxa3xx_clkregs, ARRAY_SIZE(pxa3xx_clkregs));
+               clkdev_add_table(pxa3xx_clkregs, ARRAY_SIZE(pxa3xx_clkregs));
 
                if ((ret = pxa_init_dma(IRQ_DMA, 32)))
                        return ret;
index 9f293438e020cb124e36cf4b370a5c43b0379c19..90bd4ef71b2cae9b426d0bf5e707c2a441a35e1c 100644 (file)
@@ -346,10 +346,7 @@ static struct clk_lookup lookups[] = {
 
 static int __init clk_init(void)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(lookups); i++)
-               clkdev_add(&lookups[i]);
+       clkdev_add_table(lookups, ARRAY_SIZE(lookups));
        return 0;
 }
 arch_initcall(clk_init);
index 932d8af180624a7415bdb5a09aafcb4b3235adb0..86622289b74e97950cabe4817bfaa5fc1f378e12 100644 (file)
@@ -33,7 +33,7 @@
 #error "Unknown RealView platform"
 #endif
 
-               .macro  addruart,rx
+               .macro  addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                 @ MMU enabled?
                moveq   \rx,      #0x10000000
index fe0de1b507ac20b6305b49ff341e8a0b575251ab..a2a4c68614073f37d0ec8ac0e47a40556571fffb 100644 (file)
@@ -18,4 +18,4 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-#define VMALLOC_END            0xf8000000
+#define VMALLOC_END            0xf8000000UL
index b2a939ffdcdeed21a9f63e5199eade9e15d7f351..6fc8d66395dc373d48935ec26c7364da1561ca90 100644 (file)
@@ -11,7 +11,7 @@
  *
 */
 
-               .macro  addruart,rx
+               .macro  addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                 @ MMU enabled?
                moveq   \rx, #0x03000000
index 4c29a89ad0770566b4969a84354af3d2e4f76b14..0eef78b4a6ed6fa24cddf346dfe55afeaf28a2e8 100644 (file)
@@ -19,7 +19,7 @@
 #define S3C2410_UART1_OFF (0x4000)
 #define SHIFT_2440TXF (14-9)
 
-       .macro addruart, rx
+       .macro addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1
                ldreq   \rx, = S3C24XX_PA_UART
index f0ef0ab475f68bb9c7e6f5c8aea515e1001cf196..239476b81f3b4fd643410401fad18c1b646739ef 100644 (file)
@@ -10,7 +10,7 @@
 #include <mach/map.h>
 #include <plat/regs-serial.h>
 
-       .macro addruart, rx
+       .macro addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1
                ldreq   \rx, = S3C24XX_PA_UART
index 4d4fe48495898fd20d284e5e23da2ca6fd0f738f..914656820794062b578b4cde002a9a2ecd0ed378 100644 (file)
@@ -12,6 +12,6 @@
 #ifndef __ASM_ARCH_VMALLOC_H
 #define __ASM_ARCH_VMALLOC_H
 
-#define VMALLOC_END      (0xE0000000)
+#define VMALLOC_END      (0xe0000000UL)
 
 #endif /* __ASM_ARCH_VMALLOC_H */
index b18ac5266dfc333d9196a564a565341bb4168cb9..5c88875d6a3f57054f29ec6a91e4f9ade5d8e385 100644 (file)
@@ -21,7 +21,7 @@
         * aligned and add in the offset when we load the value here.
         */
 
-       .macro addruart, rx
+       .macro addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1
                ldreq   \rx, = S3C_PA_UART
index 9d142ccf654bbab3fa046b0d9576b4982025eb78..e181f5789482fcd7943777b1343d99eb86654ff1 100644 (file)
@@ -22,7 +22,7 @@
         * aligned and add in the offset when we load the value here.
         */
 
-       .macro addruart, rx
+       .macro addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1
                ldreq   \rx, = S3C_PA_UART
index 1f0634d92702a29c3540d59356d5cc5afd841e85..336adccea54232ef50f7b43367f824c26bc20163 100644 (file)
@@ -12,7 +12,7 @@
 */
 #include <mach/hardware.h>
 
-               .macro  addruart,rx
+               .macro  addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                 @ MMU enabled?
                moveq   \rx, #0x80000000        @ physical base address
index ec8fdc5a3606bb80be5b32e7f990c44a47e89b4d..b3d0023984803dc17f7716427318ee0626844688 100644 (file)
@@ -1,4 +1,4 @@
 /*
  * arch/arm/mach-sa1100/include/mach/vmalloc.h
  */
-#define VMALLOC_END       (0xe8000000)
+#define VMALLOC_END       (0xe8000000UL)
index f97a7626bd587d39884e160e0877be571382e5f2..50f071c5bf4d603656a01a9c8c2865bf07ee2eb9 100644 (file)
@@ -11,7 +11,7 @@
  *
 */
 
-               .macro  addruart,rx
+               .macro  addruart, rx, tmp
                mov     \rx, #0xe0000000
                orr     \rx, \rx, #0x000003f8
                .endm
index 111f7ea32b384bd6e492d1cb1c0cf9635632c035..5af71d5ba6656c648fc724a36b66e6d419389a1d 100644 (file)
@@ -610,34 +610,34 @@ EXPORT_SYMBOL(clk_get_rate);
 
 static unsigned long clk_round_rate_mclk(struct clk *clk, unsigned long rate)
 {
-       if (rate >= 18900000)
+       if (rate <= 18900000)
                return 18900000;
-       if (rate >= 20800000)
+       if (rate <= 20800000)
                return 20800000;
-       if (rate >= 23100000)
+       if (rate <= 23100000)
                return 23100000;
-       if (rate >= 26000000)
+       if (rate <= 26000000)
                return 26000000;
-       if (rate >= 29700000)
+       if (rate <= 29700000)
                return 29700000;
-       if (rate >= 34700000)
+       if (rate <= 34700000)
                return 34700000;
-       if (rate >= 41600000)
+       if (rate <= 41600000)
                return 41600000;
-       if (rate >= 52000000)
+       if (rate <= 52000000)
                return 52000000;
        return -EINVAL;
 }
 
 static unsigned long clk_round_rate_cpuclk(struct clk *clk, unsigned long rate)
 {
-       if (rate >= 13000000)
+       if (rate <= 13000000)
                return 13000000;
-       if (rate >= 52000000)
+       if (rate <= 52000000)
                return 52000000;
-       if (rate >= 104000000)
+       if (rate <= 104000000)
                return 104000000;
-       if (rate >= 208000000)
+       if (rate <= 208000000)
                return 208000000;
        return -EINVAL;
 }
@@ -1276,11 +1276,8 @@ static struct clk_lookup lookups[] = {
 
 static void __init clk_register(void)
 {
-       int i;
-
        /* Register the lookups */
-       for (i = 0; i < ARRAY_SIZE(lookups); i++)
-               clkdev_add(&lookups[i]);
+       clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 }
 
 /*
index 653e25be3dd82df532b4b3a508fb45e393b00876..01b50313914cf99fd8738d288495eb18bc2919c9 100644 (file)
@@ -3,7 +3,7 @@
  * arch/arm/mach-u300/core.c
  *
  *
- * Copyright (C) 2007-2009 ST-Ericsson AB
+ * Copyright (C) 2007-2010 ST-Ericsson AB
  * License terms: GNU General Public License (GPL) version 2
  * Core platform support, IRQ handling and device definitions.
  * Author: Linus Walleij <linus.walleij@stericsson.com>
@@ -19,6 +19,7 @@
 #include <linux/amba/bus.h>
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
+#include <mach/coh901318.h>
 
 #include <asm/types.h>
 #include <asm/setup.h>
@@ -29,6 +30,7 @@
 
 #include <mach/hardware.h>
 #include <mach/syscon.h>
+#include <mach/dma_channels.h>
 
 #include "clock.h"
 #include "mmc.h"
@@ -372,8 +374,1019 @@ static struct resource ave_resources[] = {
        },
 };
 
+static struct resource dma_resource[] = {
+       {
+               .start = U300_DMAC_BASE,
+               .end = U300_DMAC_BASE + PAGE_SIZE - 1,
+               .flags =  IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_U300_DMA,
+               .end = IRQ_U300_DMA,
+               .flags =  IORESOURCE_IRQ,
+       }
+};
+
+#ifdef CONFIG_MACH_U300_BS335
+/* points out all dma slave channels.
+ * Syntax is [A1, B1, A2, B2, .... ,-1,-1]
+ * Select all channels from A to B, end of list is marked with -1,-1
+ */
+static int dma_slave_channels[] = {
+       U300_DMA_MSL_TX_0, U300_DMA_SPI_RX,
+       U300_DMA_UART1_TX, U300_DMA_UART1_RX, -1, -1};
+
+/* points out all dma memcpy channels. */
+static int dma_memcpy_channels[] = {
+       U300_DMA_GENERAL_PURPOSE_0, U300_DMA_GENERAL_PURPOSE_8, -1, -1};
+
+#else /* CONFIG_MACH_U300_BS335 */
+
+static int dma_slave_channels[] = {U300_DMA_MSL_TX_0, U300_DMA_SPI_RX, -1, -1};
+static int dma_memcpy_channels[] = {
+       U300_DMA_GENERAL_PURPOSE_0, U300_DMA_GENERAL_PURPOSE_10, -1, -1};
+
+#endif
+
+/** register dma for memory access
+ *
+ * active  1 means dma intends to access memory
+ *         0 means dma wont access memory
+ */
+static void coh901318_access_memory_state(struct device *dev, bool active)
+{
+}
+
+#define flags_memcpy_config (COH901318_CX_CFG_CH_DISABLE | \
+                       COH901318_CX_CFG_RM_MEMORY_TO_MEMORY | \
+                       COH901318_CX_CFG_LCR_DISABLE | \
+                       COH901318_CX_CFG_TC_IRQ_ENABLE | \
+                       COH901318_CX_CFG_BE_IRQ_ENABLE)
+#define flags_memcpy_lli_chained (COH901318_CX_CTRL_TC_ENABLE | \
+                       COH901318_CX_CTRL_BURST_COUNT_32_BYTES | \
+                       COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | \
+                       COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE | \
+                       COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | \
+                       COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | \
+                       COH901318_CX_CTRL_MASTER_MODE_M1RW | \
+                       COH901318_CX_CTRL_TCP_DISABLE | \
+                       COH901318_CX_CTRL_TC_IRQ_DISABLE | \
+                       COH901318_CX_CTRL_HSP_DISABLE | \
+                       COH901318_CX_CTRL_HSS_DISABLE | \
+                       COH901318_CX_CTRL_DDMA_LEGACY | \
+                       COH901318_CX_CTRL_PRDD_SOURCE)
+#define flags_memcpy_lli (COH901318_CX_CTRL_TC_ENABLE | \
+                       COH901318_CX_CTRL_BURST_COUNT_32_BYTES | \
+                       COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | \
+                       COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE | \
+                       COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | \
+                       COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | \
+                       COH901318_CX_CTRL_MASTER_MODE_M1RW | \
+                       COH901318_CX_CTRL_TCP_DISABLE | \
+                       COH901318_CX_CTRL_TC_IRQ_DISABLE | \
+                       COH901318_CX_CTRL_HSP_DISABLE | \
+                       COH901318_CX_CTRL_HSS_DISABLE | \
+                       COH901318_CX_CTRL_DDMA_LEGACY | \
+                       COH901318_CX_CTRL_PRDD_SOURCE)
+#define flags_memcpy_lli_last (COH901318_CX_CTRL_TC_ENABLE | \
+                       COH901318_CX_CTRL_BURST_COUNT_32_BYTES | \
+                       COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | \
+                       COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE | \
+                       COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | \
+                       COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | \
+                       COH901318_CX_CTRL_MASTER_MODE_M1RW | \
+                       COH901318_CX_CTRL_TCP_DISABLE | \
+                       COH901318_CX_CTRL_TC_IRQ_ENABLE | \
+                       COH901318_CX_CTRL_HSP_DISABLE | \
+                       COH901318_CX_CTRL_HSS_DISABLE | \
+                       COH901318_CX_CTRL_DDMA_LEGACY | \
+                       COH901318_CX_CTRL_PRDD_SOURCE)
+
+const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = {
+       {
+               .number = U300_DMA_MSL_TX_0,
+               .name = "MSL TX 0",
+               .priority_high = 0,
+               .dev_addr = U300_MSL_BASE + 0 * 0x40 + 0x20,
+       },
+       {
+               .number = U300_DMA_MSL_TX_1,
+               .name = "MSL TX 1",
+               .priority_high = 0,
+               .dev_addr = U300_MSL_BASE + 1 * 0x40 + 0x20,
+               .param.config = COH901318_CX_CFG_CH_DISABLE |
+                               COH901318_CX_CFG_LCR_DISABLE |
+                               COH901318_CX_CFG_TC_IRQ_ENABLE |
+                               COH901318_CX_CFG_BE_IRQ_ENABLE,
+               .param.ctrl_lli_chained = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
+                               COH901318_CX_CTRL_TCP_DISABLE |
+                               COH901318_CX_CTRL_TC_IRQ_DISABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_LEGACY |
+                               COH901318_CX_CTRL_PRDD_SOURCE,
+               .param.ctrl_lli = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
+                               COH901318_CX_CTRL_TCP_ENABLE |
+                               COH901318_CX_CTRL_TC_IRQ_DISABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_LEGACY |
+                               COH901318_CX_CTRL_PRDD_SOURCE,
+               .param.ctrl_lli_last = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
+                               COH901318_CX_CTRL_TCP_ENABLE |
+                               COH901318_CX_CTRL_TC_IRQ_ENABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_LEGACY |
+                               COH901318_CX_CTRL_PRDD_SOURCE,
+       },
+       {
+               .number = U300_DMA_MSL_TX_2,
+               .name = "MSL TX 2",
+               .priority_high = 0,
+               .dev_addr = U300_MSL_BASE + 2 * 0x40 + 0x20,
+               .param.config = COH901318_CX_CFG_CH_DISABLE |
+                               COH901318_CX_CFG_LCR_DISABLE |
+                               COH901318_CX_CFG_TC_IRQ_ENABLE |
+                               COH901318_CX_CFG_BE_IRQ_ENABLE,
+               .param.ctrl_lli_chained = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
+                               COH901318_CX_CTRL_TCP_DISABLE |
+                               COH901318_CX_CTRL_TC_IRQ_DISABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_LEGACY |
+                               COH901318_CX_CTRL_PRDD_SOURCE,
+               .param.ctrl_lli = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
+                               COH901318_CX_CTRL_TCP_ENABLE |
+                               COH901318_CX_CTRL_TC_IRQ_DISABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_LEGACY |
+                               COH901318_CX_CTRL_PRDD_SOURCE,
+               .param.ctrl_lli_last = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
+                               COH901318_CX_CTRL_TCP_ENABLE |
+                               COH901318_CX_CTRL_TC_IRQ_ENABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_LEGACY |
+                               COH901318_CX_CTRL_PRDD_SOURCE,
+               .desc_nbr_max = 10,
+       },
+       {
+               .number = U300_DMA_MSL_TX_3,
+               .name = "MSL TX 3",
+               .priority_high = 0,
+               .dev_addr = U300_MSL_BASE + 3 * 0x40 + 0x20,
+               .param.config = COH901318_CX_CFG_CH_DISABLE |
+                               COH901318_CX_CFG_LCR_DISABLE |
+                               COH901318_CX_CFG_TC_IRQ_ENABLE |
+                               COH901318_CX_CFG_BE_IRQ_ENABLE,
+               .param.ctrl_lli_chained = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
+                               COH901318_CX_CTRL_TCP_DISABLE |
+                               COH901318_CX_CTRL_TC_IRQ_DISABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_LEGACY |
+                               COH901318_CX_CTRL_PRDD_SOURCE,
+               .param.ctrl_lli = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
+                               COH901318_CX_CTRL_TCP_ENABLE |
+                               COH901318_CX_CTRL_TC_IRQ_DISABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_LEGACY |
+                               COH901318_CX_CTRL_PRDD_SOURCE,
+               .param.ctrl_lli_last = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
+                               COH901318_CX_CTRL_TCP_ENABLE |
+                               COH901318_CX_CTRL_TC_IRQ_ENABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_LEGACY |
+                               COH901318_CX_CTRL_PRDD_SOURCE,
+       },
+       {
+               .number = U300_DMA_MSL_TX_4,
+               .name = "MSL TX 4",
+               .priority_high = 0,
+               .dev_addr = U300_MSL_BASE + 4 * 0x40 + 0x20,
+               .param.config = COH901318_CX_CFG_CH_DISABLE |
+                               COH901318_CX_CFG_LCR_DISABLE |
+                               COH901318_CX_CFG_TC_IRQ_ENABLE |
+                               COH901318_CX_CFG_BE_IRQ_ENABLE,
+               .param.ctrl_lli_chained = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
+                               COH901318_CX_CTRL_TCP_DISABLE |
+                               COH901318_CX_CTRL_TC_IRQ_DISABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_LEGACY |
+                               COH901318_CX_CTRL_PRDD_SOURCE,
+               .param.ctrl_lli = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
+                               COH901318_CX_CTRL_TCP_ENABLE |
+                               COH901318_CX_CTRL_TC_IRQ_DISABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_LEGACY |
+                               COH901318_CX_CTRL_PRDD_SOURCE,
+               .param.ctrl_lli_last = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
+                               COH901318_CX_CTRL_TCP_ENABLE |
+                               COH901318_CX_CTRL_TC_IRQ_ENABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_LEGACY |
+                               COH901318_CX_CTRL_PRDD_SOURCE,
+       },
+       {
+               .number = U300_DMA_MSL_TX_5,
+               .name = "MSL TX 5",
+               .priority_high = 0,
+               .dev_addr = U300_MSL_BASE + 5 * 0x40 + 0x20,
+       },
+       {
+               .number = U300_DMA_MSL_TX_6,
+               .name = "MSL TX 6",
+               .priority_high = 0,
+               .dev_addr = U300_MSL_BASE + 6 * 0x40 + 0x20,
+       },
+       {
+               .number = U300_DMA_MSL_RX_0,
+               .name = "MSL RX 0",
+               .priority_high = 0,
+               .dev_addr = U300_MSL_BASE + 0 * 0x40 + 0x220,
+       },
+       {
+               .number = U300_DMA_MSL_RX_1,
+               .name = "MSL RX 1",
+               .priority_high = 0,
+               .dev_addr = U300_MSL_BASE + 1 * 0x40 + 0x220,
+               .param.config = COH901318_CX_CFG_CH_DISABLE |
+                               COH901318_CX_CFG_LCR_DISABLE |
+                               COH901318_CX_CFG_TC_IRQ_ENABLE |
+                               COH901318_CX_CFG_BE_IRQ_ENABLE,
+               .param.ctrl_lli_chained = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
+                               COH901318_CX_CTRL_TCP_DISABLE |
+                               COH901318_CX_CTRL_TC_IRQ_DISABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
+                               COH901318_CX_CTRL_PRDD_DEST,
+               .param.ctrl_lli = 0,
+               .param.ctrl_lli_last = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
+                               COH901318_CX_CTRL_TCP_DISABLE |
+                               COH901318_CX_CTRL_TC_IRQ_ENABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
+                               COH901318_CX_CTRL_PRDD_DEST,
+       },
+       {
+               .number = U300_DMA_MSL_RX_2,
+               .name = "MSL RX 2",
+               .priority_high = 0,
+               .dev_addr = U300_MSL_BASE + 2 * 0x40 + 0x220,
+               .param.config = COH901318_CX_CFG_CH_DISABLE |
+                               COH901318_CX_CFG_LCR_DISABLE |
+                               COH901318_CX_CFG_TC_IRQ_ENABLE |
+                               COH901318_CX_CFG_BE_IRQ_ENABLE,
+               .param.ctrl_lli_chained = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
+                               COH901318_CX_CTRL_TCP_DISABLE |
+                               COH901318_CX_CTRL_TC_IRQ_DISABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
+                               COH901318_CX_CTRL_PRDD_DEST,
+               .param.ctrl_lli = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
+                               COH901318_CX_CTRL_TCP_DISABLE |
+                               COH901318_CX_CTRL_TC_IRQ_ENABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
+                               COH901318_CX_CTRL_PRDD_DEST,
+               .param.ctrl_lli_last = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
+                               COH901318_CX_CTRL_TCP_DISABLE |
+                               COH901318_CX_CTRL_TC_IRQ_ENABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
+                               COH901318_CX_CTRL_PRDD_DEST,
+       },
+       {
+               .number = U300_DMA_MSL_RX_3,
+               .name = "MSL RX 3",
+               .priority_high = 0,
+               .dev_addr = U300_MSL_BASE + 3 * 0x40 + 0x220,
+               .param.config = COH901318_CX_CFG_CH_DISABLE |
+                               COH901318_CX_CFG_LCR_DISABLE |
+                               COH901318_CX_CFG_TC_IRQ_ENABLE |
+                               COH901318_CX_CFG_BE_IRQ_ENABLE,
+               .param.ctrl_lli_chained = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
+                               COH901318_CX_CTRL_TCP_DISABLE |
+                               COH901318_CX_CTRL_TC_IRQ_DISABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
+                               COH901318_CX_CTRL_PRDD_DEST,
+               .param.ctrl_lli = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
+                               COH901318_CX_CTRL_TCP_DISABLE |
+                               COH901318_CX_CTRL_TC_IRQ_ENABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
+                               COH901318_CX_CTRL_PRDD_DEST,
+               .param.ctrl_lli_last = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
+                               COH901318_CX_CTRL_TCP_DISABLE |
+                               COH901318_CX_CTRL_TC_IRQ_ENABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
+                               COH901318_CX_CTRL_PRDD_DEST,
+       },
+       {
+               .number = U300_DMA_MSL_RX_4,
+               .name = "MSL RX 4",
+               .priority_high = 0,
+               .dev_addr = U300_MSL_BASE + 4 * 0x40 + 0x220,
+               .param.config = COH901318_CX_CFG_CH_DISABLE |
+                               COH901318_CX_CFG_LCR_DISABLE |
+                               COH901318_CX_CFG_TC_IRQ_ENABLE |
+                               COH901318_CX_CFG_BE_IRQ_ENABLE,
+               .param.ctrl_lli_chained = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
+                               COH901318_CX_CTRL_TCP_DISABLE |
+                               COH901318_CX_CTRL_TC_IRQ_DISABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
+                               COH901318_CX_CTRL_PRDD_DEST,
+               .param.ctrl_lli = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
+                               COH901318_CX_CTRL_TCP_DISABLE |
+                               COH901318_CX_CTRL_TC_IRQ_ENABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
+                               COH901318_CX_CTRL_PRDD_DEST,
+               .param.ctrl_lli_last = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
+                               COH901318_CX_CTRL_TCP_DISABLE |
+                               COH901318_CX_CTRL_TC_IRQ_ENABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
+                               COH901318_CX_CTRL_PRDD_DEST,
+       },
+       {
+               .number = U300_DMA_MSL_RX_5,
+               .name = "MSL RX 5",
+               .priority_high = 0,
+               .dev_addr = U300_MSL_BASE + 5 * 0x40 + 0x220,
+               .param.config = COH901318_CX_CFG_CH_DISABLE |
+                               COH901318_CX_CFG_LCR_DISABLE |
+                               COH901318_CX_CFG_TC_IRQ_ENABLE |
+                               COH901318_CX_CFG_BE_IRQ_ENABLE,
+               .param.ctrl_lli_chained = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
+                               COH901318_CX_CTRL_TCP_DISABLE |
+                               COH901318_CX_CTRL_TC_IRQ_DISABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
+                               COH901318_CX_CTRL_PRDD_DEST,
+               .param.ctrl_lli = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
+                               COH901318_CX_CTRL_TCP_DISABLE |
+                               COH901318_CX_CTRL_TC_IRQ_ENABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
+                               COH901318_CX_CTRL_PRDD_DEST,
+               .param.ctrl_lli_last = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
+                               COH901318_CX_CTRL_TCP_DISABLE |
+                               COH901318_CX_CTRL_TC_IRQ_ENABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
+                               COH901318_CX_CTRL_PRDD_DEST,
+       },
+       {
+               .number = U300_DMA_MSL_RX_6,
+               .name = "MSL RX 6",
+               .priority_high = 0,
+               .dev_addr = U300_MSL_BASE + 6 * 0x40 + 0x220,
+       },
+       {
+               .number = U300_DMA_MMCSD_RX_TX,
+               .name = "MMCSD RX TX",
+               .priority_high = 0,
+               .dev_addr =  U300_MMCSD_BASE + 0x080,
+               .param.config = COH901318_CX_CFG_CH_DISABLE |
+                               COH901318_CX_CFG_LCR_DISABLE |
+                               COH901318_CX_CFG_TC_IRQ_ENABLE |
+                               COH901318_CX_CFG_BE_IRQ_ENABLE,
+               .param.ctrl_lli_chained = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_MASTER_MODE_M1RW |
+                               COH901318_CX_CTRL_TCP_ENABLE |
+                               COH901318_CX_CTRL_TC_IRQ_ENABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_LEGACY,
+               .param.ctrl_lli = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_MASTER_MODE_M1RW |
+                               COH901318_CX_CTRL_TCP_ENABLE |
+                               COH901318_CX_CTRL_TC_IRQ_ENABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_LEGACY,
+               .param.ctrl_lli_last = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_MASTER_MODE_M1RW |
+                               COH901318_CX_CTRL_TCP_DISABLE |
+                               COH901318_CX_CTRL_TC_IRQ_ENABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_LEGACY,
+
+       },
+       {
+               .number = U300_DMA_MSPRO_TX,
+               .name = "MSPRO TX",
+               .priority_high = 0,
+       },
+       {
+               .number = U300_DMA_MSPRO_RX,
+               .name = "MSPRO RX",
+               .priority_high = 0,
+       },
+       {
+               .number = U300_DMA_UART0_TX,
+               .name = "UART0 TX",
+               .priority_high = 0,
+       },
+       {
+               .number = U300_DMA_UART0_RX,
+               .name = "UART0 RX",
+               .priority_high = 0,
+       },
+       {
+               .number = U300_DMA_APEX_TX,
+               .name = "APEX TX",
+               .priority_high = 0,
+       },
+       {
+               .number = U300_DMA_APEX_RX,
+               .name = "APEX RX",
+               .priority_high = 0,
+       },
+       {
+               .number = U300_DMA_PCM_I2S0_TX,
+               .name = "PCM I2S0 TX",
+               .priority_high = 1,
+               .dev_addr = U300_PCM_I2S0_BASE + 0x14,
+               .param.config = COH901318_CX_CFG_CH_DISABLE |
+                               COH901318_CX_CFG_LCR_DISABLE |
+                               COH901318_CX_CFG_TC_IRQ_ENABLE |
+                               COH901318_CX_CFG_BE_IRQ_ENABLE,
+               .param.ctrl_lli_chained = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M1RW |
+                               COH901318_CX_CTRL_TCP_DISABLE |
+                               COH901318_CX_CTRL_TC_IRQ_DISABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_LEGACY |
+                               COH901318_CX_CTRL_PRDD_SOURCE,
+               .param.ctrl_lli = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M1RW |
+                               COH901318_CX_CTRL_TCP_ENABLE |
+                               COH901318_CX_CTRL_TC_IRQ_DISABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_LEGACY |
+                               COH901318_CX_CTRL_PRDD_SOURCE,
+               .param.ctrl_lli_last = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M1RW |
+                               COH901318_CX_CTRL_TCP_ENABLE |
+                               COH901318_CX_CTRL_TC_IRQ_ENABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_LEGACY |
+                               COH901318_CX_CTRL_PRDD_SOURCE,
+       },
+       {
+               .number = U300_DMA_PCM_I2S0_RX,
+               .name = "PCM I2S0 RX",
+               .priority_high = 1,
+               .dev_addr = U300_PCM_I2S0_BASE + 0x10,
+               .param.config = COH901318_CX_CFG_CH_DISABLE |
+                               COH901318_CX_CFG_LCR_DISABLE |
+                               COH901318_CX_CFG_TC_IRQ_ENABLE |
+                               COH901318_CX_CFG_BE_IRQ_ENABLE,
+               .param.ctrl_lli_chained = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M1RW |
+                               COH901318_CX_CTRL_TCP_DISABLE |
+                               COH901318_CX_CTRL_TC_IRQ_DISABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_LEGACY |
+                               COH901318_CX_CTRL_PRDD_DEST,
+               .param.ctrl_lli = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M1RW |
+                               COH901318_CX_CTRL_TCP_ENABLE |
+                               COH901318_CX_CTRL_TC_IRQ_DISABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_LEGACY |
+                               COH901318_CX_CTRL_PRDD_DEST,
+               .param.ctrl_lli_last = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M1RW |
+                               COH901318_CX_CTRL_TCP_ENABLE |
+                               COH901318_CX_CTRL_TC_IRQ_ENABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_LEGACY |
+                               COH901318_CX_CTRL_PRDD_DEST,
+       },
+       {
+               .number = U300_DMA_PCM_I2S1_TX,
+               .name = "PCM I2S1 TX",
+               .priority_high = 1,
+               .dev_addr =  U300_PCM_I2S1_BASE + 0x14,
+               .param.config = COH901318_CX_CFG_CH_DISABLE |
+                               COH901318_CX_CFG_LCR_DISABLE |
+                               COH901318_CX_CFG_TC_IRQ_ENABLE |
+                               COH901318_CX_CFG_BE_IRQ_ENABLE,
+               .param.ctrl_lli_chained = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M1RW |
+                               COH901318_CX_CTRL_TCP_DISABLE |
+                               COH901318_CX_CTRL_TC_IRQ_DISABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_LEGACY |
+                               COH901318_CX_CTRL_PRDD_SOURCE,
+               .param.ctrl_lli = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M1RW |
+                               COH901318_CX_CTRL_TCP_ENABLE |
+                               COH901318_CX_CTRL_TC_IRQ_DISABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_LEGACY |
+                               COH901318_CX_CTRL_PRDD_SOURCE,
+               .param.ctrl_lli_last = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M1RW |
+                               COH901318_CX_CTRL_TCP_ENABLE |
+                               COH901318_CX_CTRL_TC_IRQ_ENABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_LEGACY |
+                               COH901318_CX_CTRL_PRDD_SOURCE,
+       },
+       {
+               .number = U300_DMA_PCM_I2S1_RX,
+               .name = "PCM I2S1 RX",
+               .priority_high = 1,
+               .dev_addr = U300_PCM_I2S1_BASE + 0x10,
+               .param.config = COH901318_CX_CFG_CH_DISABLE |
+                               COH901318_CX_CFG_LCR_DISABLE |
+                               COH901318_CX_CFG_TC_IRQ_ENABLE |
+                               COH901318_CX_CFG_BE_IRQ_ENABLE,
+               .param.ctrl_lli_chained = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M1RW |
+                               COH901318_CX_CTRL_TCP_DISABLE |
+                               COH901318_CX_CTRL_TC_IRQ_DISABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_LEGACY |
+                               COH901318_CX_CTRL_PRDD_DEST,
+               .param.ctrl_lli = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M1RW |
+                               COH901318_CX_CTRL_TCP_ENABLE |
+                               COH901318_CX_CTRL_TC_IRQ_DISABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_LEGACY |
+                               COH901318_CX_CTRL_PRDD_DEST,
+               .param.ctrl_lli_last = 0 |
+                               COH901318_CX_CTRL_TC_ENABLE |
+                               COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
+                               COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+                               COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+                               COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+                               COH901318_CX_CTRL_MASTER_MODE_M1RW |
+                               COH901318_CX_CTRL_TCP_ENABLE |
+                               COH901318_CX_CTRL_TC_IRQ_ENABLE |
+                               COH901318_CX_CTRL_HSP_ENABLE |
+                               COH901318_CX_CTRL_HSS_DISABLE |
+                               COH901318_CX_CTRL_DDMA_LEGACY |
+                               COH901318_CX_CTRL_PRDD_DEST,
+       },
+       {
+               .number = U300_DMA_XGAM_CDI,
+               .name = "XGAM CDI",
+               .priority_high = 0,
+       },
+       {
+               .number = U300_DMA_XGAM_PDI,
+               .name = "XGAM PDI",
+               .priority_high = 0,
+       },
+       {
+               .number = U300_DMA_SPI_TX,
+               .name = "SPI TX",
+               .priority_high = 0,
+       },
+       {
+               .number = U300_DMA_SPI_RX,
+               .name = "SPI RX",
+               .priority_high = 0,
+       },
+       {
+               .number = U300_DMA_GENERAL_PURPOSE_0,
+               .name = "GENERAL 00",
+               .priority_high = 0,
+
+               .param.config = flags_memcpy_config,
+               .param.ctrl_lli_chained = flags_memcpy_lli_chained,
+               .param.ctrl_lli = flags_memcpy_lli,
+               .param.ctrl_lli_last = flags_memcpy_lli_last,
+       },
+       {
+               .number = U300_DMA_GENERAL_PURPOSE_1,
+               .name = "GENERAL 01",
+               .priority_high = 0,
+
+               .param.config = flags_memcpy_config,
+               .param.ctrl_lli_chained = flags_memcpy_lli_chained,
+               .param.ctrl_lli = flags_memcpy_lli,
+               .param.ctrl_lli_last = flags_memcpy_lli_last,
+       },
+       {
+               .number = U300_DMA_GENERAL_PURPOSE_2,
+               .name = "GENERAL 02",
+               .priority_high = 0,
+
+               .param.config = flags_memcpy_config,
+               .param.ctrl_lli_chained = flags_memcpy_lli_chained,
+               .param.ctrl_lli = flags_memcpy_lli,
+               .param.ctrl_lli_last = flags_memcpy_lli_last,
+       },
+       {
+               .number = U300_DMA_GENERAL_PURPOSE_3,
+               .name = "GENERAL 03",
+               .priority_high = 0,
+
+               .param.config = flags_memcpy_config,
+               .param.ctrl_lli_chained = flags_memcpy_lli_chained,
+               .param.ctrl_lli = flags_memcpy_lli,
+               .param.ctrl_lli_last = flags_memcpy_lli_last,
+       },
+       {
+               .number = U300_DMA_GENERAL_PURPOSE_4,
+               .name = "GENERAL 04",
+               .priority_high = 0,
+
+               .param.config = flags_memcpy_config,
+               .param.ctrl_lli_chained = flags_memcpy_lli_chained,
+               .param.ctrl_lli = flags_memcpy_lli,
+               .param.ctrl_lli_last = flags_memcpy_lli_last,
+       },
+       {
+               .number = U300_DMA_GENERAL_PURPOSE_5,
+               .name = "GENERAL 05",
+               .priority_high = 0,
+
+               .param.config = flags_memcpy_config,
+               .param.ctrl_lli_chained = flags_memcpy_lli_chained,
+               .param.ctrl_lli = flags_memcpy_lli,
+               .param.ctrl_lli_last = flags_memcpy_lli_last,
+       },
+       {
+               .number = U300_DMA_GENERAL_PURPOSE_6,
+               .name = "GENERAL 06",
+               .priority_high = 0,
+
+               .param.config = flags_memcpy_config,
+               .param.ctrl_lli_chained = flags_memcpy_lli_chained,
+               .param.ctrl_lli = flags_memcpy_lli,
+               .param.ctrl_lli_last = flags_memcpy_lli_last,
+       },
+       {
+               .number = U300_DMA_GENERAL_PURPOSE_7,
+               .name = "GENERAL 07",
+               .priority_high = 0,
+
+               .param.config = flags_memcpy_config,
+               .param.ctrl_lli_chained = flags_memcpy_lli_chained,
+               .param.ctrl_lli = flags_memcpy_lli,
+               .param.ctrl_lli_last = flags_memcpy_lli_last,
+       },
+       {
+               .number = U300_DMA_GENERAL_PURPOSE_8,
+               .name = "GENERAL 08",
+               .priority_high = 0,
+
+               .param.config = flags_memcpy_config,
+               .param.ctrl_lli_chained = flags_memcpy_lli_chained,
+               .param.ctrl_lli = flags_memcpy_lli,
+               .param.ctrl_lli_last = flags_memcpy_lli_last,
+       },
+#ifdef CONFIG_MACH_U300_BS335
+       {
+               .number = U300_DMA_UART1_TX,
+               .name = "UART1 TX",
+               .priority_high = 0,
+       },
+       {
+               .number = U300_DMA_UART1_RX,
+               .name = "UART1 RX",
+               .priority_high = 0,
+       }
+#else
+       {
+               .number = U300_DMA_GENERAL_PURPOSE_9,
+               .name = "GENERAL 09",
+               .priority_high = 0,
+
+               .param.config = flags_memcpy_config,
+               .param.ctrl_lli_chained = flags_memcpy_lli_chained,
+               .param.ctrl_lli = flags_memcpy_lli,
+               .param.ctrl_lli_last = flags_memcpy_lli_last,
+       },
+       {
+               .number = U300_DMA_GENERAL_PURPOSE_10,
+               .name = "GENERAL 10",
+               .priority_high = 0,
+
+               .param.config = flags_memcpy_config,
+               .param.ctrl_lli_chained = flags_memcpy_lli_chained,
+               .param.ctrl_lli = flags_memcpy_lli,
+               .param.ctrl_lli_last = flags_memcpy_lli_last,
+       }
+#endif
+};
+
+
+static struct coh901318_platform coh901318_platform = {
+       .chans_slave = dma_slave_channels,
+       .chans_memcpy = dma_memcpy_channels,
+       .access_memory_state = coh901318_access_memory_state,
+       .chan_conf = chan_config,
+       .max_channels = U300_DMA_CHANNELS,
+};
+
 static struct platform_device wdog_device = {
-       .name = "wdog",
+       .name = "coh901327_wdog",
        .id = -1,
        .num_resources = ARRAY_SIZE(wdog_resources),
        .resource = wdog_resources,
@@ -428,11 +1441,23 @@ static struct platform_device ave_device = {
        .resource = ave_resources,
 };
 
+static struct platform_device dma_device = {
+       .name           = "coh901318",
+       .id             = -1,
+       .resource       = dma_resource,
+       .num_resources  = ARRAY_SIZE(dma_resource),
+       .dev = {
+               .platform_data = &coh901318_platform,
+               .coherent_dma_mask = ~0,
+       },
+};
+
 /*
  * Notice that AMBA devices are initialized before platform devices.
  *
  */
 static struct platform_device *platform_devs[] __initdata = {
+       &dma_device,
        &i2c0_device,
        &i2c1_device,
        &keypad_device,
index 0b35826b7d1d419a5daf875cdf1cfc215fac726c..5f61fd45a0c8a1dee47baa305ca3aa49d07fac01 100644 (file)
@@ -546,7 +546,7 @@ static void gpio_set_initial_values(void)
        for (i = 0; i < U300_GPIO_MAX; i++) {
                val = 0;
                for (j = 0; j < 8; j++)
-                       val |= (u32)((u300_gpio_config[i][j].pull_up == DISABLE_PULL_UP)) << j;
+                       val |= (u32)((u300_gpio_config[i][j].pull_up == DISABLE_PULL_UP) << j);
                local_irq_save(flags);
                writel(val, virtbase + U300_GPIO_PXPER + i * U300_GPIO_PORTX_SPACING);
                local_irq_restore(flags);
index f3a1cbbeeab3876a91ec8da8411bcb09d2d78901..ca4a028c26613097811977bf2f2d14be592aee18 100644 (file)
@@ -10,7 +10,7 @@
  */
 #include <mach/hardware.h>
 
-       .macro  addruart,rx
+       .macro  addruart, rx, tmp
        /* If we move the adress using MMU, use this. */
        mrc     p15, 0, \rx, c1, c0
        tst     \rx, #1                 @ MMU enabled?
diff --git a/arch/arm/mach-u300/include/mach/dma_channels.h b/arch/arm/mach-u300/include/mach/dma_channels.h
new file mode 100644 (file)
index 0000000..b239149
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ *
+ * arch/arm/mach-u300/include/mach/dma_channels.h
+ *
+ *
+ * Copyright (C) 2007-2009 ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2
+ * Map file for the U300 dma driver.
+ * Author: Per Friden <per.friden@stericsson.com>
+ */
+
+#ifndef DMA_CHANNELS_H
+#define DMA_CHANNELS_H
+
+#define U300_DMA_MSL_TX_0             0
+#define U300_DMA_MSL_TX_1             1
+#define U300_DMA_MSL_TX_2             2
+#define U300_DMA_MSL_TX_3             3
+#define U300_DMA_MSL_TX_4             4
+#define U300_DMA_MSL_TX_5             5
+#define U300_DMA_MSL_TX_6             6
+#define U300_DMA_MSL_RX_0             7
+#define U300_DMA_MSL_RX_1             8
+#define U300_DMA_MSL_RX_2             9
+#define U300_DMA_MSL_RX_3             10
+#define U300_DMA_MSL_RX_4             11
+#define U300_DMA_MSL_RX_5             12
+#define U300_DMA_MSL_RX_6             13
+#define U300_DMA_MMCSD_RX_TX          14
+#define U300_DMA_MSPRO_TX             15
+#define U300_DMA_MSPRO_RX             16
+#define U300_DMA_UART0_TX             17
+#define U300_DMA_UART0_RX             18
+#define U300_DMA_APEX_TX              19
+#define U300_DMA_APEX_RX              20
+#define U300_DMA_PCM_I2S0_TX          21
+#define U300_DMA_PCM_I2S0_RX          22
+#define U300_DMA_PCM_I2S1_TX          23
+#define U300_DMA_PCM_I2S1_RX          24
+#define U300_DMA_XGAM_CDI             25
+#define U300_DMA_XGAM_PDI             26
+#define U300_DMA_SPI_TX               27
+#define U300_DMA_SPI_RX               28
+#define U300_DMA_GENERAL_PURPOSE_0    29
+#define U300_DMA_GENERAL_PURPOSE_1    30
+#define U300_DMA_GENERAL_PURPOSE_2    31
+#define U300_DMA_GENERAL_PURPOSE_3    32
+#define U300_DMA_GENERAL_PURPOSE_4    33
+#define U300_DMA_GENERAL_PURPOSE_5    34
+#define U300_DMA_GENERAL_PURPOSE_6    35
+#define U300_DMA_GENERAL_PURPOSE_7    36
+#define U300_DMA_GENERAL_PURPOSE_8    37
+#ifdef CONFIG_MACH_U300_BS335
+#define U300_DMA_UART1_TX             38
+#define U300_DMA_UART1_RX             39
+#else
+#define U300_DMA_GENERAL_PURPOSE_9    38
+#define U300_DMA_GENERAL_PURPOSE_10   39
+#endif
+
+#ifdef CONFIG_MACH_U300_BS335
+#define U300_DMA_DEVICE_CHANNELS      32
+#else
+#define U300_DMA_DEVICE_CHANNELS      30
+#endif
+#define U300_DMA_CHANNELS             40
+
+
+#endif /* DMA_CHANNELS_H */
index b00c51a66fbe59cf948d14fc8582ded0a3374eca..ec423b92b81dd25ffd69f623bb190c6114108653 100644 (file)
@@ -9,4 +9,4 @@
  * End must be above the I/O registers and on an even 2MiB boundary.
  * Author: Linus Walleij <linus.walleij@stericsson.com>
  */
-#define VMALLOC_END    0xfe800000
+#define VMALLOC_END    0xfe800000UL
index aa5afbcc90f9a752dcc49f18010efe2e9315d0b6..803aec1d672823e44854be50a29a931e1914e409 100644 (file)
@@ -22,6 +22,7 @@
 #include <asm/mach/arch.h>
 
 #include <plat/mtu.h>
+#include <plat/i2c.h>
 
 #include <mach/hardware.h>
 #include <mach/setup.h>
@@ -108,11 +109,96 @@ static struct amba_device pl022_device = {
        .periphid = SSP_PER_ID,
 };
 
+static struct amba_device pl031_device = {
+       .dev = {
+               .init_name = "pl031",
+       },
+       .res = {
+               .start = U8500_RTC_BASE,
+               .end = U8500_RTC_BASE + SZ_4K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       .irq = {IRQ_RTC_RTT, NO_IRQ},
+};
+
+#define U8500_I2C_RESOURCES(id, size)          \
+static struct resource u8500_i2c_resources_##id[] = {  \
+       [0] = {                                 \
+               .start  = U8500_I2C##id##_BASE, \
+               .end    = U8500_I2C##id##_BASE + size - 1, \
+               .flags  = IORESOURCE_MEM,       \
+       },                                      \
+       [1] = {                                 \
+               .start  = IRQ_I2C##id,          \
+               .end    = IRQ_I2C##id,          \
+               .flags  = IORESOURCE_IRQ        \
+       }                                       \
+}
+
+U8500_I2C_RESOURCES(0, SZ_4K);
+U8500_I2C_RESOURCES(1, SZ_4K);
+U8500_I2C_RESOURCES(2, SZ_4K);
+U8500_I2C_RESOURCES(3, SZ_4K);
+
+#define U8500_I2C_CONTROLLER(id, _slsu, _tft, _rft, clk, _sm) \
+static struct nmk_i2c_controller u8500_i2c_##id = { \
+       /*                              \
+        * slave data setup time, which is      \
+        * 250 ns,100ns,10ns which is 14,6,2    \
+        * respectively for a 48 Mhz    \
+        * i2c clock                    \
+        */                             \
+       .slsu           = _slsu,        \
+       /* Tx FIFO threshold */         \
+       .tft            = _tft,         \
+       /* Rx FIFO threshold */         \
+       .rft            = _rft,         \
+       /* std. mode operation */       \
+       .clk_freq       = clk,          \
+       .sm             = _sm,          \
+}
+
+/*
+ * The board uses 4 i2c controllers, initialize all of
+ * them with slave data setup time of 250 ns,
+ * Tx & Rx FIFO threshold values as 1 and standard
+ * mode of operation
+ */
+U8500_I2C_CONTROLLER(0, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD);
+U8500_I2C_CONTROLLER(1, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD);
+U8500_I2C_CONTROLLER(2,        0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD);
+U8500_I2C_CONTROLLER(3,        0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD);
+
+#define U8500_I2C_PDEVICE(cid)         \
+static struct platform_device i2c_controller##cid = { \
+       .name = "nmk-i2c",              \
+       .id      = cid,                 \
+       .num_resources = 2,             \
+       .resource = u8500_i2c_resources_##cid,  \
+       .dev = {                        \
+               .platform_data = &u8500_i2c_##cid \
+       }                               \
+}
+
+U8500_I2C_PDEVICE(0);
+U8500_I2C_PDEVICE(1);
+U8500_I2C_PDEVICE(2);
+U8500_I2C_PDEVICE(3);
+
 static struct amba_device *amba_devs[] __initdata = {
        &uart0_device,
        &uart1_device,
        &uart2_device,
        &pl022_device,
+       &pl031_device,
+};
+
+/* add any platform devices here - TODO */
+static struct platform_device *platform_devs[] __initdata = {
+       &i2c_controller0,
+       &i2c_controller1,
+       &i2c_controller2,
+       &i2c_controller3,
 };
 
 static void __init u8500_timer_init(void)
@@ -139,6 +225,8 @@ static void __init u8500_init_machine(void)
        for (i = 0; i < ARRAY_SIZE(amba_devs); i++)
                amba_device_register(amba_devs[i], &iomem_resource);
 
+       platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));
+
        spi_register_board_info(u8500_spi_devices,
                        ARRAY_SIZE(u8500_spi_devices));
 
index 20b6ebb6783aa7bb8f3a60356b780b66ff784a95..8359a73d0041c0b988cd4ecea50a77ac92f71093 100644 (file)
@@ -85,11 +85,8 @@ static struct clk_lookup lookups[] = {
 
 static int __init clk_init(void)
 {
-       int i;
-
        /* register the clock lookups */
-       for (i = 0; i < ARRAY_SIZE(lookups); i++)
-               clkdev_add(&lookups[i]);
+       clkdev_add_table(lookups, ARRAY_SIZE(lookups));
        return 0;
 }
 arch_initcall(clk_init);
index 5f05e5850f7162de73125305c7c124140cf93d1e..397bc1f9ed94aed1b56abfd669b55b0fa5976ae8 100644 (file)
@@ -33,6 +33,7 @@ static struct platform_device *platform_devs[] __initdata = {
 
 /* minimum static i/o mapping required to boot U8500 platforms */
 static struct map_desc u8500_io_desc[] __initdata = {
+       __IO_DEV_DESC(U8500_UART2_BASE, SZ_4K),
        __IO_DEV_DESC(U8500_GIC_CPU_BASE, SZ_4K),
        __IO_DEV_DESC(U8500_GIC_DIST_BASE, SZ_4K),
        __IO_DEV_DESC(U8500_MTU0_BASE, SZ_4K),
index 8f21b6a95dce5b13f6fc9becfe4c4606145366ee..09cbfda8aee5af8d6359fb25a0a525d99f11414f 100644 (file)
@@ -8,12 +8,13 @@
  * published by the Free Software Foundation.
  *
  */
-       .macro  addruart,rx
+#include <mach/hardware.h>
+
+       .macro  addruart, rx, tmp
        mrc     p15, 0, \rx, c1, c0
-       tst     \rx, #1                 @MMU enabled?
-       moveq   \rx, #0x80000000        @MMU off, Physical address
-       movne   \rx, #0xF0000000        @MMU on, Virtual address
-       orr     \rx, \rx, #0x7000
+       tst     \rx, #1                                 @ MMU enabled?
+       ldreq   \rx, =U8500_UART2_BASE                  @ no, physical address
+       ldrne   \rx, =IO_ADDRESS(U8500_UART2_BASE)      @ yes, virtual address
        .endm
 
 #include <asm/hardware/debug-pl01x.S>
index 86cdbbce1842f8b8bd089261fb0a444eaeb5564c..a4945cb41172c09e80620f19fad10bfe499fcb55 100644 (file)
@@ -15,4 +15,4 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-#define VMALLOC_END    0xf0000000
+#define VMALLOC_END    0xf0000000UL
index e13be7c444ca83acb774b3865b4055b81f908b0f..9ddb49b1cb719119c2df40c3e807a4c90b36e712 100644 (file)
@@ -851,8 +851,7 @@ void __init versatile_init(void)
 {
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(lookups); i++)
-               clkdev_add(&lookups[i]);
+       clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
        platform_device_register(&versatile_flash_device);
        platform_device_register(&versatile_i2c_device);
index b4ac00eacf6876fa69719f47537f9a1899b8ff93..6fea7199c626742d4e39afcaadecd5e32ad39e99 100644 (file)
@@ -11,7 +11,7 @@
  *
 */
 
-               .macro  addruart,rx
+               .macro  addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                 @ MMU enabled?
                moveq   \rx,      #0x10000000
index b785994bab0a64fbe2bf5cf6f2cdd8e67f10306c..2c371ff22e517ad17776902f5af31e8e198d1a66 100644 (file)
@@ -90,12 +90,3 @@ void nuc900_subclk_enable(struct clk *clk, int enable)
 
        __raw_writel(clken, W90X900_VA_CLKPWR + SUBCLK);
 }
-
-
-void clks_register(struct clk_lookup *clks, size_t num)
-{
-       int i;
-
-       for (i = 0; i < num; i++)
-               clkdev_add(&clks[i]);
-}
index f5816a06eed6aa415bffd21b5dbd708266d404dc..c56ddab3d9128acce33ba0d293a3dcfa29bcd08c 100644 (file)
@@ -14,7 +14,6 @@
 
 void nuc900_clk_enable(struct clk *clk, int enable);
 void nuc900_subclk_enable(struct clk *clk, int enable);
-void clks_register(struct clk_lookup *clks, size_t num);
 
 struct clk {
        unsigned long           cken;
index 20dc0c96214dcae4e93bb67910e5c0027eb6cf8f..642207e18198db20777ef475a27ada0bd2ae0c3d 100644 (file)
@@ -45,6 +45,7 @@ static struct map_desc nuc900_iodesc[] __initdata = {
        IODESC_ENT(UART),
        IODESC_ENT(TIMER),
        IODESC_ENT(EBI),
+       IODESC_ENT(GPIO),
 };
 
 /* Initial clock declarations. */
@@ -68,6 +69,11 @@ static DEFINE_CLK(gdma, 27);
 static DEFINE_CLK(adc, 28);
 static DEFINE_CLK(usi, 29);
 static DEFINE_CLK(ext, 0);
+static DEFINE_CLK(timer0, 19);
+static DEFINE_CLK(timer1, 20);
+static DEFINE_CLK(timer2, 21);
+static DEFINE_CLK(timer3, 22);
+static DEFINE_CLK(timer4, 23);
 
 static struct clk_lookup nuc900_clkregs[] = {
        DEF_CLKLOOK(&clk_lcd, "nuc900-lcd", NULL),
@@ -90,6 +96,11 @@ static struct clk_lookup nuc900_clkregs[] = {
        DEF_CLKLOOK(&clk_adc, "nuc900-adc", NULL),
        DEF_CLKLOOK(&clk_usi, "nuc900-spi", NULL),
        DEF_CLKLOOK(&clk_ext, NULL, "ext"),
+       DEF_CLKLOOK(&clk_timer0, NULL, "timer0"),
+       DEF_CLKLOOK(&clk_timer1, NULL, "timer1"),
+       DEF_CLKLOOK(&clk_timer2, NULL, "timer2"),
+       DEF_CLKLOOK(&clk_timer3, NULL, "timer3"),
+       DEF_CLKLOOK(&clk_timer4, NULL, "timer4"),
 };
 
 /* Initial serial platform data */
@@ -208,6 +219,6 @@ void __init nuc900_map_io(struct map_desc *mach_desc, int mach_size)
 
 void __init nuc900_init_clocks(void)
 {
-       clks_register(nuc900_clkregs, ARRAY_SIZE(nuc900_clkregs));
+       clkdev_add_table(nuc900_clkregs, ARRAY_SIZE(nuc900_clkregs));
 }
 
index 2f9dfb928533391e292feb51cd45aaec5543a3a3..b067e44500a48b84796fbfae6db045ac69b21265 100644 (file)
@@ -18,6 +18,6 @@
 #ifndef __ASM_ARCH_VMALLOC_H
 #define __ASM_ARCH_VMALLOC_H
 
-#define VMALLOC_END      (0xE0000000)
+#define VMALLOC_END      (0xe0000000UL)
 
 #endif /* __ASM_ARCH_VMALLOC_H */
index baf638487a2d530acaf30c7cab9581b3ec5b6f47..c4ed9f93f646be93fbdcc048a326c5d7db995bcd 100644 (file)
@@ -399,7 +399,7 @@ config CPU_V6
 config CPU_32v6K
        bool "Support ARM V6K processor extensions" if !SMP
        depends on CPU_V6
-       default y if SMP && !ARCH_MX3
+       default y if SMP && !(ARCH_MX3 || ARCH_OMAP2)
        help
          Say Y here if your ARMv6 processor supports the 'K' extension.
          This enables the kernel to use some instructions not present
@@ -410,7 +410,7 @@ config CPU_32v6K
 # ARMv7
 config CPU_V7
        bool "Support ARM V7 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX
-       select CPU_32v6K
+       select CPU_32v6K if !ARCH_OMAP2
        select CPU_32v7
        select CPU_ABRT_EV7
        select CPU_PABRT_V7
@@ -754,7 +754,7 @@ config CACHE_FEROCEON_L2_WRITETHROUGH
 config CACHE_L2X0
        bool "Enable the L2x0 outer cache controller"
        depends on REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176 || \
-                  REALVIEW_EB_A9MP || ARCH_MX35 || ARCH_MX31 || MACH_REALVIEW_PBX || ARCH_NOMADIK
+                  REALVIEW_EB_A9MP || ARCH_MX35 || ARCH_MX31 || MACH_REALVIEW_PBX || ARCH_NOMADIK || ARCH_OMAP4
        default y
        select OUTER_CACHE
        help
@@ -779,5 +779,5 @@ config CACHE_XSC3L2
 
 config ARM_L1_CACHE_SHIFT
        int
-       default 6 if ARCH_OMAP3 || ARCH_S5PC1XX
+       default 6 if ARM_L1_CACHE_SHIFT_6
        default 5
index 62820eda84d9ea89bb1ec729b8934c626a74c20a..edddd66faac6bb9a1f08e8ca144b3677cb9fac3c 100644 (file)
@@ -901,11 +901,7 @@ static int __init alignment_init(void)
 #ifdef CONFIG_PROC_FS
        struct proc_dir_entry *res;
 
-       res = proc_mkdir("cpu", NULL);
-       if (!res)
-               return -ENOMEM;
-
-       res = create_proc_entry("alignment", S_IWUSR | S_IRUGO, res);
+       res = create_proc_entry("cpu/alignment", S_IWUSR | S_IRUGO, NULL);
        if (!res)
                return -ENOMEM;
 
index a89444a3c016f0c2ecee35d38655b109664bc91b..7148e53e6078fff5b32a5d8d87a5ce1658095ae3 100644 (file)
@@ -157,7 +157,7 @@ ENTRY(fa_flush_kern_dcache_area)
  *     - start  - virtual start address
  *     - end    - virtual end address
  */
-ENTRY(fa_dma_inv_range)
+fa_dma_inv_range:
        tst     r0, #CACHE_DLINESIZE - 1
        bic     r0, r0, #CACHE_DLINESIZE - 1
        mcrne   p15, 0, r0, c7, c14, 1          @ clean & invalidate D entry
@@ -180,7 +180,7 @@ ENTRY(fa_dma_inv_range)
  *     - start  - virtual start address
  *     - end    - virtual end address
  */
-ENTRY(fa_dma_clean_range)
+fa_dma_clean_range:
        bic     r0, r0, #CACHE_DLINESIZE - 1
 1:     mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
        add     r0, r0, #CACHE_DLINESIZE
@@ -205,6 +205,30 @@ ENTRY(fa_dma_flush_range)
        mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer
        mov     pc, lr
 
+/*
+ *     dma_map_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(fa_dma_map_area)
+       add     r1, r1, r0
+       cmp     r2, #DMA_TO_DEVICE
+       beq     fa_dma_clean_range
+       bcs     fa_dma_inv_range
+       b       fa_dma_flush_range
+ENDPROC(fa_dma_map_area)
+
+/*
+ *     dma_unmap_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(fa_dma_unmap_area)
+       mov     pc, lr
+ENDPROC(fa_dma_unmap_area)
+
        __INITDATA
 
        .type   fa_cache_fns, #object
@@ -215,7 +239,7 @@ ENTRY(fa_cache_fns)
        .long   fa_coherent_kern_range
        .long   fa_coherent_user_range
        .long   fa_flush_kern_dcache_area
-       .long   fa_dma_inv_range
-       .long   fa_dma_clean_range
+       .long   fa_dma_map_area
+       .long   fa_dma_unmap_area
        .long   fa_dma_flush_range
        .size   fa_cache_fns, . - fa_cache_fns
index cb8fc6573b1b2c9dedbeeec0f9a87c491a78ba85..07334632d3e2761293e1880b2486a2e85c3437e4 100644 (file)
@@ -42,6 +42,57 @@ static inline void cache_sync(void)
        cache_wait(base + L2X0_CACHE_SYNC, 1);
 }
 
+static inline void l2x0_clean_line(unsigned long addr)
+{
+       void __iomem *base = l2x0_base;
+       cache_wait(base + L2X0_CLEAN_LINE_PA, 1);
+       writel(addr, base + L2X0_CLEAN_LINE_PA);
+}
+
+static inline void l2x0_inv_line(unsigned long addr)
+{
+       void __iomem *base = l2x0_base;
+       cache_wait(base + L2X0_INV_LINE_PA, 1);
+       writel(addr, base + L2X0_INV_LINE_PA);
+}
+
+#ifdef CONFIG_PL310_ERRATA_588369
+static void debug_writel(unsigned long val)
+{
+       extern void omap_smc1(u32 fn, u32 arg);
+
+       /*
+        * Texas Instrument secure monitor api to modify the
+        * PL310 Debug Control Register.
+        */
+       omap_smc1(0x100, val);
+}
+
+static inline void l2x0_flush_line(unsigned long addr)
+{
+       void __iomem *base = l2x0_base;
+
+       /* Clean by PA followed by Invalidate by PA */
+       cache_wait(base + L2X0_CLEAN_LINE_PA, 1);
+       writel(addr, base + L2X0_CLEAN_LINE_PA);
+       cache_wait(base + L2X0_INV_LINE_PA, 1);
+       writel(addr, base + L2X0_INV_LINE_PA);
+}
+#else
+
+/* Optimised out for non-errata case */
+static inline void debug_writel(unsigned long val)
+{
+}
+
+static inline void l2x0_flush_line(unsigned long addr)
+{
+       void __iomem *base = l2x0_base;
+       cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1);
+       writel(addr, base + L2X0_CLEAN_INV_LINE_PA);
+}
+#endif
+
 static inline void l2x0_inv_all(void)
 {
        unsigned long flags;
@@ -62,23 +113,24 @@ static void l2x0_inv_range(unsigned long start, unsigned long end)
        spin_lock_irqsave(&l2x0_lock, flags);
        if (start & (CACHE_LINE_SIZE - 1)) {
                start &= ~(CACHE_LINE_SIZE - 1);
-               cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1);
-               writel(start, base + L2X0_CLEAN_INV_LINE_PA);
+               debug_writel(0x03);
+               l2x0_flush_line(start);
+               debug_writel(0x00);
                start += CACHE_LINE_SIZE;
        }
 
        if (end & (CACHE_LINE_SIZE - 1)) {
                end &= ~(CACHE_LINE_SIZE - 1);
-               cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1);
-               writel(end, base + L2X0_CLEAN_INV_LINE_PA);
+               debug_writel(0x03);
+               l2x0_flush_line(end);
+               debug_writel(0x00);
        }
 
        while (start < end) {
                unsigned long blk_end = start + min(end - start, 4096UL);
 
                while (start < blk_end) {
-                       cache_wait(base + L2X0_INV_LINE_PA, 1);
-                       writel(start, base + L2X0_INV_LINE_PA);
+                       l2x0_inv_line(start);
                        start += CACHE_LINE_SIZE;
                }
 
@@ -103,8 +155,7 @@ static void l2x0_clean_range(unsigned long start, unsigned long end)
                unsigned long blk_end = start + min(end - start, 4096UL);
 
                while (start < blk_end) {
-                       cache_wait(base + L2X0_CLEAN_LINE_PA, 1);
-                       writel(start, base + L2X0_CLEAN_LINE_PA);
+                       l2x0_clean_line(start);
                        start += CACHE_LINE_SIZE;
                }
 
@@ -128,11 +179,12 @@ static void l2x0_flush_range(unsigned long start, unsigned long end)
        while (start < end) {
                unsigned long blk_end = start + min(end - start, 4096UL);
 
+               debug_writel(0x03);
                while (start < blk_end) {
-                       cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1);
-                       writel(start, base + L2X0_CLEAN_INV_LINE_PA);
+                       l2x0_flush_line(start);
                        start += CACHE_LINE_SIZE;
                }
+               debug_writel(0x00);
 
                if (blk_end < end) {
                        spin_unlock_irqrestore(&l2x0_lock, flags);
index 2a482731ea36914f2f6ca2b6bb4299e7dee84742..c2ff3c599feed47eb77d92190d29958fb95e8315 100644 (file)
@@ -83,20 +83,6 @@ ENTRY(v3_coherent_user_range)
 ENTRY(v3_flush_kern_dcache_area)
        /* FALLTHROUGH */
 
-/*
- *     dma_inv_range(start, end)
- *
- *     Invalidate (discard) the specified virtual address range.
- *     May not write back any entries.  If 'start' or 'end'
- *     are not cache line aligned, those lines must be written
- *     back.
- *
- *     - start  - virtual start address
- *     - end    - virtual end address
- */
-ENTRY(v3_dma_inv_range)
-       /* FALLTHROUGH */
-
 /*
  *     dma_flush_range(start, end)
  *
@@ -108,18 +94,29 @@ ENTRY(v3_dma_inv_range)
 ENTRY(v3_dma_flush_range)
        mov     r0, #0
        mcr     p15, 0, r0, c7, c0, 0           @ flush ID cache
+       mov     pc, lr
+
+/*
+ *     dma_unmap_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(v3_dma_unmap_area)
+       teq     r2, #DMA_TO_DEVICE
+       bne     v3_dma_flush_range
        /* FALLTHROUGH */
 
 /*
- *     dma_clean_range(start, end)
- *
- *     Clean (write back) the specified virtual address range.
- *
- *     - start  - virtual start address
- *     - end    - virtual end address
+ *     dma_map_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
  */
-ENTRY(v3_dma_clean_range)
+ENTRY(v3_dma_map_area)
        mov     pc, lr
+ENDPROC(v3_dma_unmap_area)
+ENDPROC(v3_dma_map_area)
 
        __INITDATA
 
@@ -131,7 +128,7 @@ ENTRY(v3_cache_fns)
        .long   v3_coherent_kern_range
        .long   v3_coherent_user_range
        .long   v3_flush_kern_dcache_area
-       .long   v3_dma_inv_range
-       .long   v3_dma_clean_range
+       .long   v3_dma_map_area
+       .long   v3_dma_unmap_area
        .long   v3_dma_flush_range
        .size   v3_cache_fns, . - v3_cache_fns
index 5c7da3e372e94faa6f85a07b2c154730140f44b6..4810f7e3e8139ea8bed712cc4b9cea792660d99a 100644 (file)
@@ -93,20 +93,6 @@ ENTRY(v4_coherent_user_range)
 ENTRY(v4_flush_kern_dcache_area)
        /* FALLTHROUGH */
 
-/*
- *     dma_inv_range(start, end)
- *
- *     Invalidate (discard) the specified virtual address range.
- *     May not write back any entries.  If 'start' or 'end'
- *     are not cache line aligned, those lines must be written
- *     back.
- *
- *     - start  - virtual start address
- *     - end    - virtual end address
- */
-ENTRY(v4_dma_inv_range)
-       /* FALLTHROUGH */
-
 /*
  *     dma_flush_range(start, end)
  *
@@ -120,18 +106,29 @@ ENTRY(v4_dma_flush_range)
        mov     r0, #0
        mcr     p15, 0, r0, c7, c7, 0           @ flush ID cache
 #endif
+       mov     pc, lr
+
+/*
+ *     dma_unmap_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(v4_dma_unmap_area)
+       teq     r2, #DMA_TO_DEVICE
+       bne     v4_dma_flush_range
        /* FALLTHROUGH */
 
 /*
- *     dma_clean_range(start, end)
- *
- *     Clean (write back) the specified virtual address range.
- *
- *     - start  - virtual start address
- *     - end    - virtual end address
+ *     dma_map_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
  */
-ENTRY(v4_dma_clean_range)
+ENTRY(v4_dma_map_area)
        mov     pc, lr
+ENDPROC(v4_dma_unmap_area)
+ENDPROC(v4_dma_map_area)
 
        __INITDATA
 
@@ -143,7 +140,7 @@ ENTRY(v4_cache_fns)
        .long   v4_coherent_kern_range
        .long   v4_coherent_user_range
        .long   v4_flush_kern_dcache_area
-       .long   v4_dma_inv_range
-       .long   v4_dma_clean_range
+       .long   v4_dma_map_area
+       .long   v4_dma_unmap_area
        .long   v4_dma_flush_range
        .size   v4_cache_fns, . - v4_cache_fns
index 3dbedf1ec0e7790612385b34def041378af5f0d9..df8368afa102771bb99c19045abac26abb42e656 100644 (file)
@@ -173,7 +173,7 @@ ENTRY(v4wb_coherent_user_range)
  *     - start  - virtual start address
  *     - end    - virtual end address
  */
-ENTRY(v4wb_dma_inv_range)
+v4wb_dma_inv_range:
        tst     r0, #CACHE_DLINESIZE - 1
        bic     r0, r0, #CACHE_DLINESIZE - 1
        mcrne   p15, 0, r0, c7, c10, 1          @ clean D entry
@@ -194,7 +194,7 @@ ENTRY(v4wb_dma_inv_range)
  *     - start  - virtual start address
  *     - end    - virtual end address
  */
-ENTRY(v4wb_dma_clean_range)
+v4wb_dma_clean_range:
        bic     r0, r0, #CACHE_DLINESIZE - 1
 1:     mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
        add     r0, r0, #CACHE_DLINESIZE
@@ -216,6 +216,30 @@ ENTRY(v4wb_dma_clean_range)
        .globl  v4wb_dma_flush_range
        .set    v4wb_dma_flush_range, v4wb_coherent_kern_range
 
+/*
+ *     dma_map_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(v4wb_dma_map_area)
+       add     r1, r1, r0
+       cmp     r2, #DMA_TO_DEVICE
+       beq     v4wb_dma_clean_range
+       bcs     v4wb_dma_inv_range
+       b       v4wb_dma_flush_range
+ENDPROC(v4wb_dma_map_area)
+
+/*
+ *     dma_unmap_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(v4wb_dma_unmap_area)
+       mov     pc, lr
+ENDPROC(v4wb_dma_unmap_area)
+
        __INITDATA
 
        .type   v4wb_cache_fns, #object
@@ -226,7 +250,7 @@ ENTRY(v4wb_cache_fns)
        .long   v4wb_coherent_kern_range
        .long   v4wb_coherent_user_range
        .long   v4wb_flush_kern_dcache_area
-       .long   v4wb_dma_inv_range
-       .long   v4wb_dma_clean_range
+       .long   v4wb_dma_map_area
+       .long   v4wb_dma_unmap_area
        .long   v4wb_dma_flush_range
        .size   v4wb_cache_fns, . - v4wb_cache_fns
index b3b7410270b48e6bf3414de930e2eff0010cf6b3..45c70312f43bb1db9f49ae9591283d243b072ae8 100644 (file)
@@ -142,23 +142,12 @@ ENTRY(v4wt_flush_kern_dcache_area)
  *     - start  - virtual start address
  *     - end    - virtual end address
  */
-ENTRY(v4wt_dma_inv_range)
+v4wt_dma_inv_range:
        bic     r0, r0, #CACHE_DLINESIZE - 1
 1:     mcr     p15, 0, r0, c7, c6, 1           @ invalidate D entry
        add     r0, r0, #CACHE_DLINESIZE
        cmp     r0, r1
        blo     1b
-       /* FALLTHROUGH */
-
-/*
- *     dma_clean_range(start, end)
- *
- *     Clean the specified virtual address range.
- *
- *     - start  - virtual start address
- *     - end    - virtual end address
- */
-ENTRY(v4wt_dma_clean_range)
        mov     pc, lr
 
 /*
@@ -172,6 +161,29 @@ ENTRY(v4wt_dma_clean_range)
        .globl  v4wt_dma_flush_range
        .equ    v4wt_dma_flush_range, v4wt_dma_inv_range
 
+/*
+ *     dma_unmap_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(v4wt_dma_unmap_area)
+       add     r1, r1, r0
+       teq     r2, #DMA_TO_DEVICE
+       bne     v4wt_dma_inv_range
+       /* FALLTHROUGH */
+
+/*
+ *     dma_map_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(v4wt_dma_map_area)
+       mov     pc, lr
+ENDPROC(v4wt_dma_unmap_area)
+ENDPROC(v4wt_dma_map_area)
+
        __INITDATA
 
        .type   v4wt_cache_fns, #object
@@ -182,7 +194,7 @@ ENTRY(v4wt_cache_fns)
        .long   v4wt_coherent_kern_range
        .long   v4wt_coherent_user_range
        .long   v4wt_flush_kern_dcache_area
-       .long   v4wt_dma_inv_range
-       .long   v4wt_dma_clean_range
+       .long   v4wt_dma_map_area
+       .long   v4wt_dma_unmap_area
        .long   v4wt_dma_flush_range
        .size   v4wt_cache_fns, . - v4wt_cache_fns
index 4ba0a24ce6f58341bcf0a78aef56531709e7b774..9d89c67a1cc3902c32b5aed501d27f28b091695c 100644 (file)
@@ -195,7 +195,7 @@ ENTRY(v6_flush_kern_dcache_area)
  *     - start   - virtual start address of region
  *     - end     - virtual end address of region
  */
-ENTRY(v6_dma_inv_range)
+v6_dma_inv_range:
        tst     r0, #D_CACHE_LINE_SIZE - 1
        bic     r0, r0, #D_CACHE_LINE_SIZE - 1
 #ifdef HARVARD_CACHE
@@ -228,7 +228,7 @@ ENTRY(v6_dma_inv_range)
  *     - start   - virtual start address of region
  *     - end     - virtual end address of region
  */
-ENTRY(v6_dma_clean_range)
+v6_dma_clean_range:
        bic     r0, r0, #D_CACHE_LINE_SIZE - 1
 1:
 #ifdef HARVARD_CACHE
@@ -263,6 +263,32 @@ ENTRY(v6_dma_flush_range)
        mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer
        mov     pc, lr
 
+/*
+ *     dma_map_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(v6_dma_map_area)
+       add     r1, r1, r0
+       teq     r2, #DMA_FROM_DEVICE
+       beq     v6_dma_inv_range
+       b       v6_dma_clean_range
+ENDPROC(v6_dma_map_area)
+
+/*
+ *     dma_unmap_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(v6_dma_unmap_area)
+       add     r1, r1, r0
+       teq     r2, #DMA_TO_DEVICE
+       bne     v6_dma_inv_range
+       mov     pc, lr
+ENDPROC(v6_dma_unmap_area)
+
        __INITDATA
 
        .type   v6_cache_fns, #object
@@ -273,7 +299,7 @@ ENTRY(v6_cache_fns)
        .long   v6_coherent_kern_range
        .long   v6_coherent_user_range
        .long   v6_flush_kern_dcache_area
-       .long   v6_dma_inv_range
-       .long   v6_dma_clean_range
+       .long   v6_dma_map_area
+       .long   v6_dma_unmap_area
        .long   v6_dma_flush_range
        .size   v6_cache_fns, . - v6_cache_fns
index 9073db849fb46a75f08c18c1ae9790614696e377..bcd64f265870804532dc6012274bca6e398a0622 100644 (file)
@@ -216,7 +216,7 @@ ENDPROC(v7_flush_kern_dcache_area)
  *     - start   - virtual start address of region
  *     - end     - virtual end address of region
  */
-ENTRY(v7_dma_inv_range)
+v7_dma_inv_range:
        dcache_line_size r2, r3
        sub     r3, r2, #1
        tst     r0, r3
@@ -240,7 +240,7 @@ ENDPROC(v7_dma_inv_range)
  *     - start   - virtual start address of region
  *     - end     - virtual end address of region
  */
-ENTRY(v7_dma_clean_range)
+v7_dma_clean_range:
        dcache_line_size r2, r3
        sub     r3, r2, #1
        bic     r0, r0, r3
@@ -271,6 +271,32 @@ ENTRY(v7_dma_flush_range)
        mov     pc, lr
 ENDPROC(v7_dma_flush_range)
 
+/*
+ *     dma_map_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(v7_dma_map_area)
+       add     r1, r1, r0
+       teq     r2, #DMA_FROM_DEVICE
+       beq     v7_dma_inv_range
+       b       v7_dma_clean_range
+ENDPROC(v7_dma_map_area)
+
+/*
+ *     dma_unmap_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(v7_dma_unmap_area)
+       add     r1, r1, r0
+       teq     r2, #DMA_TO_DEVICE
+       bne     v7_dma_inv_range
+       mov     pc, lr
+ENDPROC(v7_dma_unmap_area)
+
        __INITDATA
 
        .type   v7_cache_fns, #object
@@ -281,7 +307,7 @@ ENTRY(v7_cache_fns)
        .long   v7_coherent_kern_range
        .long   v7_coherent_user_range
        .long   v7_flush_kern_dcache_area
-       .long   v7_dma_inv_range
-       .long   v7_dma_clean_range
+       .long   v7_dma_map_area
+       .long   v7_dma_unmap_area
        .long   v7_dma_flush_range
        .size   v7_cache_fns, . - v7_cache_fns
index a9e22e31eaa1135ca9997840266f3144dd587735..b0ee9ba3cfab41a52853eca727466abff88ddf27 100644 (file)
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/percpu.h>
 
 #include <asm/mmu_context.h>
 #include <asm/tlbflush.h>
 
 static DEFINE_SPINLOCK(cpu_asid_lock);
 unsigned int cpu_last_asid = ASID_FIRST_VERSION;
+#ifdef CONFIG_SMP
+DEFINE_PER_CPU(struct mm_struct *, current_mm);
+#endif
 
 /*
  * We fork()ed a process, and we need a new context for the child
@@ -26,13 +31,109 @@ unsigned int cpu_last_asid = ASID_FIRST_VERSION;
 void __init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 {
        mm->context.id = 0;
+       spin_lock_init(&mm->context.id_lock);
 }
 
+static void flush_context(void)
+{
+       /* set the reserved ASID before flushing the TLB */
+       asm("mcr        p15, 0, %0, c13, c0, 1\n" : : "r" (0));
+       isb();
+       local_flush_tlb_all();
+       if (icache_is_vivt_asid_tagged()) {
+               __flush_icache_all();
+               dsb();
+       }
+}
+
+#ifdef CONFIG_SMP
+
+static void set_mm_context(struct mm_struct *mm, unsigned int asid)
+{
+       unsigned long flags;
+
+       /*
+        * Locking needed for multi-threaded applications where the
+        * same mm->context.id could be set from different CPUs during
+        * the broadcast. This function is also called via IPI so the
+        * mm->context.id_lock has to be IRQ-safe.
+        */
+       spin_lock_irqsave(&mm->context.id_lock, flags);
+       if (likely((mm->context.id ^ cpu_last_asid) >> ASID_BITS)) {
+               /*
+                * Old version of ASID found. Set the new one and
+                * reset mm_cpumask(mm).
+                */
+               mm->context.id = asid;
+               cpumask_clear(mm_cpumask(mm));
+       }
+       spin_unlock_irqrestore(&mm->context.id_lock, flags);
+
+       /*
+        * Set the mm_cpumask(mm) bit for the current CPU.
+        */
+       cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm));
+}
+
+/*
+ * Reset the ASID on the current CPU. This function call is broadcast
+ * from the CPU handling the ASID rollover and holding cpu_asid_lock.
+ */
+static void reset_context(void *info)
+{
+       unsigned int asid;
+       unsigned int cpu = smp_processor_id();
+       struct mm_struct *mm = per_cpu(current_mm, cpu);
+
+       /*
+        * Check if a current_mm was set on this CPU as it might still
+        * be in the early booting stages and using the reserved ASID.
+        */
+       if (!mm)
+               return;
+
+       smp_rmb();
+       asid = cpu_last_asid + cpu + 1;
+
+       flush_context();
+       set_mm_context(mm, asid);
+
+       /* set the new ASID */
+       asm("mcr        p15, 0, %0, c13, c0, 1\n" : : "r" (mm->context.id));
+       isb();
+}
+
+#else
+
+static inline void set_mm_context(struct mm_struct *mm, unsigned int asid)
+{
+       mm->context.id = asid;
+       cpumask_copy(mm_cpumask(mm), cpumask_of(smp_processor_id()));
+}
+
+#endif
+
 void __new_context(struct mm_struct *mm)
 {
        unsigned int asid;
 
        spin_lock(&cpu_asid_lock);
+#ifdef CONFIG_SMP
+       /*
+        * Check the ASID again, in case the change was broadcast from
+        * another CPU before we acquired the lock.
+        */
+       if (unlikely(((mm->context.id ^ cpu_last_asid) >> ASID_BITS) == 0)) {
+               cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm));
+               spin_unlock(&cpu_asid_lock);
+               return;
+       }
+#endif
+       /*
+        * At this point, it is guaranteed that the current mm (with
+        * an old ASID) isn't active on any other CPU since the ASIDs
+        * are changed simultaneously via IPI.
+        */
        asid = ++cpu_last_asid;
        if (asid == 0)
                asid = cpu_last_asid = ASID_FIRST_VERSION;
@@ -42,20 +143,15 @@ void __new_context(struct mm_struct *mm)
         * to start a new version and flush the TLB.
         */
        if (unlikely((asid & ~ASID_MASK) == 0)) {
-               asid = ++cpu_last_asid;
-               /* set the reserved ASID before flushing the TLB */
-               asm("mcr        p15, 0, %0, c13, c0, 1  @ set reserved context ID\n"
-                   :
-                   : "r" (0));
-               isb();
-               flush_tlb_all();
-               if (icache_is_vivt_asid_tagged()) {
-                       __flush_icache_all();
-                       dsb();
-               }
+               asid = cpu_last_asid + smp_processor_id() + 1;
+               flush_context();
+#ifdef CONFIG_SMP
+               smp_wmb();
+               smp_call_function(reset_context, NULL, 1);
+#endif
+               cpu_last_asid += NR_CPUS;
        }
-       spin_unlock(&cpu_asid_lock);
 
-       cpumask_copy(mm_cpumask(mm), cpumask_of(smp_processor_id()));
-       mm->context.id = asid;
+       set_mm_context(mm, asid);
+       spin_unlock(&cpu_asid_lock);
 }
index 70997d5bee2d76d1d617a5ce5453437e51e4c009..5eb4fd93893dfa113cddf7944eeb063d968965a2 100644 (file)
@@ -68,12 +68,13 @@ feroceon_copy_user_page(void *kto, const void *kfrom)
 }
 
 void feroceon_copy_user_highpage(struct page *to, struct page *from,
-       unsigned long vaddr)
+       unsigned long vaddr, struct vm_area_struct *vma)
 {
        void *kto, *kfrom;
 
        kto = kmap_atomic(to, KM_USER0);
        kfrom = kmap_atomic(from, KM_USER1);
+       flush_cache_page(vma, vaddr, page_to_pfn(from));
        feroceon_copy_user_page(kto, kfrom);
        kunmap_atomic(kfrom, KM_USER1);
        kunmap_atomic(kto, KM_USER0);
index de9c06854ad724547b36937fcc57fa2f1905f1e0..f72303e1d804e08d7cecf2c82760a2c7a6355318 100644 (file)
@@ -38,7 +38,7 @@ v3_copy_user_page(void *kto, const void *kfrom)
 }
 
 void v3_copy_user_highpage(struct page *to, struct page *from,
-       unsigned long vaddr)
+       unsigned long vaddr, struct vm_area_struct *vma)
 {
        void *kto, *kfrom;
 
index 7370a7142b0424eba7f356151048db8cff66a38f..598c51ad50717f28d00202a9f8fd185b6a58b6a8 100644 (file)
@@ -69,7 +69,7 @@ mc_copy_user_page(void *from, void *to)
 }
 
 void v4_mc_copy_user_highpage(struct page *to, struct page *from,
-       unsigned long vaddr)
+       unsigned long vaddr, struct vm_area_struct *vma)
 {
        void *kto = kmap_atomic(to, KM_USER1);
 
index 9ab098414227e928007212f6159d8fcba88fc763..7c2eb55cd4a9263c9d3eb3e17d590cac0cc5d9b3 100644 (file)
@@ -48,12 +48,13 @@ v4wb_copy_user_page(void *kto, const void *kfrom)
 }
 
 void v4wb_copy_user_highpage(struct page *to, struct page *from,
-       unsigned long vaddr)
+       unsigned long vaddr, struct vm_area_struct *vma)
 {
        void *kto, *kfrom;
 
        kto = kmap_atomic(to, KM_USER0);
        kfrom = kmap_atomic(from, KM_USER1);
+       flush_cache_page(vma, vaddr, page_to_pfn(from));
        v4wb_copy_user_page(kto, kfrom);
        kunmap_atomic(kfrom, KM_USER1);
        kunmap_atomic(kto, KM_USER0);
index 300efafd66431ae02b042df0e065efca88424bf3..172e6a55458eb321dbf0708be20433a4daa7909f 100644 (file)
@@ -44,7 +44,7 @@ v4wt_copy_user_page(void *kto, const void *kfrom)
 }
 
 void v4wt_copy_user_highpage(struct page *to, struct page *from,
-       unsigned long vaddr)
+       unsigned long vaddr, struct vm_area_struct *vma)
 {
        void *kto, *kfrom;
 
index 0fa1319273dead26070b178751828f025d661561..8bca4dea6dfa234bbcf0c343a70f87f751de3b66 100644 (file)
@@ -34,7 +34,7 @@ static DEFINE_SPINLOCK(v6_lock);
  * attack the kernel's existing mapping of these pages.
  */
 static void v6_copy_user_highpage_nonaliasing(struct page *to,
-       struct page *from, unsigned long vaddr)
+       struct page *from, unsigned long vaddr, struct vm_area_struct *vma)
 {
        void *kto, *kfrom;
 
@@ -81,7 +81,7 @@ static void discard_old_kernel_data(void *kto)
  * Copy the page, taking account of the cache colour.
  */
 static void v6_copy_user_highpage_aliasing(struct page *to,
-       struct page *from, unsigned long vaddr)
+       struct page *from, unsigned long vaddr, struct vm_area_struct *vma)
 {
        unsigned int offset = CACHE_COLOUR(vaddr);
        unsigned long kfrom, kto;
index bc4525f5ab2326d266c828dac8c21f81a7655854..747ad4140fc75527d9c7b7409caf98e59504894d 100644 (file)
@@ -71,12 +71,13 @@ xsc3_mc_copy_user_page(void *kto, const void *kfrom)
 }
 
 void xsc3_mc_copy_user_highpage(struct page *to, struct page *from,
-       unsigned long vaddr)
+       unsigned long vaddr, struct vm_area_struct *vma)
 {
        void *kto, *kfrom;
 
        kto = kmap_atomic(to, KM_USER0);
        kfrom = kmap_atomic(from, KM_USER1);
+       flush_cache_page(vma, vaddr, page_to_pfn(from));
        xsc3_mc_copy_user_page(kto, kfrom);
        kunmap_atomic(kfrom, KM_USER1);
        kunmap_atomic(kto, KM_USER0);
index 76824d3e966a5a1b34105775aeb96b8acb086f4d..9920c0ae2096cc2c6b8c9e535dc63ab5d400afb0 100644 (file)
@@ -91,7 +91,7 @@ mc_copy_user_page(void *from, void *to)
 }
 
 void xscale_mc_copy_user_highpage(struct page *to, struct page *from,
-       unsigned long vaddr)
+       unsigned long vaddr, struct vm_area_struct *vma)
 {
        void *kto = kmap_atomic(to, KM_USER1);
 
index 26325cb5d368e504e6eb7c669b28ac3ed023e3c6..0da7eccf7749103d26e9545560256f0a8b47dce4 100644 (file)
@@ -29,9 +29,6 @@
 #error "CONSISTENT_DMA_SIZE must be multiple of 2MiB"
 #endif
 
-#define CONSISTENT_END (0xffe00000)
-#define CONSISTENT_BASE        (CONSISTENT_END - CONSISTENT_DMA_SIZE)
-
 #define CONSISTENT_OFFSET(x)   (((unsigned long)(x) - CONSISTENT_BASE) >> PAGE_SHIFT)
 #define CONSISTENT_PTE_INDEX(x) (((unsigned long)(x) - CONSISTENT_BASE) >> PGDIR_SHIFT)
 #define NUM_CONSISTENT_PTES (CONSISTENT_DMA_SIZE >> PGDIR_SHIFT)
@@ -404,78 +401,44 @@ EXPORT_SYMBOL(dma_free_coherent);
  * platforms with CONFIG_DMABOUNCE.
  * Use the driver DMA support - see dma-mapping.h (dma_sync_*)
  */
-void dma_cache_maint(const void *start, size_t size, int direction)
+void ___dma_single_cpu_to_dev(const void *kaddr, size_t size,
+       enum dma_data_direction dir)
 {
-       void (*inner_op)(const void *, const void *);
-       void (*outer_op)(unsigned long, unsigned long);
-
-       BUG_ON(!virt_addr_valid(start) || !virt_addr_valid(start + size - 1));
-
-       switch (direction) {
-       case DMA_FROM_DEVICE:           /* invalidate only */
-               inner_op = dmac_inv_range;
-               outer_op = outer_inv_range;
-               break;
-       case DMA_TO_DEVICE:             /* writeback only */
-               inner_op = dmac_clean_range;
-               outer_op = outer_clean_range;
-               break;
-       case DMA_BIDIRECTIONAL:         /* writeback and invalidate */
-               inner_op = dmac_flush_range;
-               outer_op = outer_flush_range;
-               break;
-       default:
-               BUG();
-       }
+       unsigned long paddr;
+
+       BUG_ON(!virt_addr_valid(kaddr) || !virt_addr_valid(kaddr + size - 1));
 
-       inner_op(start, start + size);
-       outer_op(__pa(start), __pa(start) + size);
+       dmac_map_area(kaddr, size, dir);
+
+       paddr = __pa(kaddr);
+       if (dir == DMA_FROM_DEVICE) {
+               outer_inv_range(paddr, paddr + size);
+       } else {
+               outer_clean_range(paddr, paddr + size);
+       }
+       /* FIXME: non-speculating: flush on bidirectional mappings? */
 }
-EXPORT_SYMBOL(dma_cache_maint);
+EXPORT_SYMBOL(___dma_single_cpu_to_dev);
 
-static void dma_cache_maint_contiguous(struct page *page, unsigned long offset,
-                                      size_t size, int direction)
+void ___dma_single_dev_to_cpu(const void *kaddr, size_t size,
+       enum dma_data_direction dir)
 {
-       void *vaddr;
-       unsigned long paddr;
-       void (*inner_op)(const void *, const void *);
-       void (*outer_op)(unsigned long, unsigned long);
-
-       switch (direction) {
-       case DMA_FROM_DEVICE:           /* invalidate only */
-               inner_op = dmac_inv_range;
-               outer_op = outer_inv_range;
-               break;
-       case DMA_TO_DEVICE:             /* writeback only */
-               inner_op = dmac_clean_range;
-               outer_op = outer_clean_range;
-               break;
-       case DMA_BIDIRECTIONAL:         /* writeback and invalidate */
-               inner_op = dmac_flush_range;
-               outer_op = outer_flush_range;
-               break;
-       default:
-               BUG();
-       }
+       BUG_ON(!virt_addr_valid(kaddr) || !virt_addr_valid(kaddr + size - 1));
 
-       if (!PageHighMem(page)) {
-               vaddr = page_address(page) + offset;
-               inner_op(vaddr, vaddr + size);
-       } else {
-               vaddr = kmap_high_get(page);
-               if (vaddr) {
-                       vaddr += offset;
-                       inner_op(vaddr, vaddr + size);
-                       kunmap_high(page);
-               }
+       /* FIXME: non-speculating: not required */
+       /* don't bother invalidating if DMA to device */
+       if (dir != DMA_TO_DEVICE) {
+               unsigned long paddr = __pa(kaddr);
+               outer_inv_range(paddr, paddr + size);
        }
 
-       paddr = page_to_phys(page) + offset;
-       outer_op(paddr, paddr + size);
+       dmac_unmap_area(kaddr, size, dir);
 }
+EXPORT_SYMBOL(___dma_single_dev_to_cpu);
 
-void dma_cache_maint_page(struct page *page, unsigned long offset,
-                         size_t size, int dir)
+static void dma_cache_maint_page(struct page *page, unsigned long offset,
+       size_t size, enum dma_data_direction dir,
+       void (*op)(const void *, size_t, int))
 {
        /*
         * A single sg entry may refer to multiple physically contiguous
@@ -486,20 +449,62 @@ void dma_cache_maint_page(struct page *page, unsigned long offset,
        size_t left = size;
        do {
                size_t len = left;
-               if (PageHighMem(page) && len + offset > PAGE_SIZE) {
-                       if (offset >= PAGE_SIZE) {
-                               page += offset / PAGE_SIZE;
-                               offset %= PAGE_SIZE;
+               void *vaddr;
+
+               if (PageHighMem(page)) {
+                       if (len + offset > PAGE_SIZE) {
+                               if (offset >= PAGE_SIZE) {
+                                       page += offset / PAGE_SIZE;
+                                       offset %= PAGE_SIZE;
+                               }
+                               len = PAGE_SIZE - offset;
                        }
-                       len = PAGE_SIZE - offset;
+                       vaddr = kmap_high_get(page);
+                       if (vaddr) {
+                               vaddr += offset;
+                               op(vaddr, len, dir);
+                               kunmap_high(page);
+                       }
+               } else {
+                       vaddr = page_address(page) + offset;
+                       op(vaddr, len, dir);
                }
-               dma_cache_maint_contiguous(page, offset, len, dir);
                offset = 0;
                page++;
                left -= len;
        } while (left);
 }
-EXPORT_SYMBOL(dma_cache_maint_page);
+
+void ___dma_page_cpu_to_dev(struct page *page, unsigned long off,
+       size_t size, enum dma_data_direction dir)
+{
+       unsigned long paddr;
+
+       dma_cache_maint_page(page, off, size, dir, dmac_map_area);
+
+       paddr = page_to_phys(page) + off;
+       if (dir == DMA_FROM_DEVICE) {
+               outer_inv_range(paddr, paddr + size);
+       } else {
+               outer_clean_range(paddr, paddr + size);
+       }
+       /* FIXME: non-speculating: flush on bidirectional mappings? */
+}
+EXPORT_SYMBOL(___dma_page_cpu_to_dev);
+
+void ___dma_page_dev_to_cpu(struct page *page, unsigned long off,
+       size_t size, enum dma_data_direction dir)
+{
+       unsigned long paddr = page_to_phys(page) + off;
+
+       /* FIXME: non-speculating: not required */
+       /* don't bother invalidating if DMA to device */
+       if (dir != DMA_TO_DEVICE)
+               outer_inv_range(paddr, paddr + size);
+
+       dma_cache_maint_page(page, off, size, dir, dmac_unmap_area);
+}
+EXPORT_SYMBOL(___dma_page_dev_to_cpu);
 
 /**
  * dma_map_sg - map a set of SG buffers for streaming mode DMA
@@ -573,8 +578,12 @@ void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
        int i;
 
        for_each_sg(sg, s, nents, i) {
-               dmabounce_sync_for_cpu(dev, sg_dma_address(s), 0,
-                                       sg_dma_len(s), dir);
+               if (!dmabounce_sync_for_cpu(dev, sg_dma_address(s), 0,
+                                           sg_dma_len(s), dir))
+                       continue;
+
+               __dma_page_dev_to_cpu(sg_page(s), s->offset,
+                                     s->length, dir);
        }
 }
 EXPORT_SYMBOL(dma_sync_sg_for_cpu);
@@ -597,9 +606,8 @@ void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
                                        sg_dma_len(s), dir))
                        continue;
 
-               if (!arch_is_coherent())
-                       dma_cache_maint_page(sg_page(s), s->offset,
-                                            s->length, dir);
+               __dma_page_cpu_to_dev(sg_page(s), s->offset,
+                                     s->length, dir);
        }
 }
 EXPORT_SYMBOL(dma_sync_sg_for_device);
index 56ee15321b005f0ae9a6cc62dfaaa5bd8ad5cf73..c9b97e9836a201ba752c069731afdf1a10b7cea1 100644 (file)
@@ -36,28 +36,12 @@ static unsigned long shared_pte_mask = L_PTE_MT_BUFFERABLE;
  * Therefore those configurations which might call adjust_pte (those
  * without CONFIG_CPU_CACHE_VIPT) cannot support split page_table_lock.
  */
-static int adjust_pte(struct vm_area_struct *vma, unsigned long address)
+static int do_adjust_pte(struct vm_area_struct *vma, unsigned long address,
+       unsigned long pfn, pte_t *ptep)
 {
-       pgd_t *pgd;
-       pmd_t *pmd;
-       pte_t *pte, entry;
+       pte_t entry = *ptep;
        int ret;
 
-       pgd = pgd_offset(vma->vm_mm, address);
-       if (pgd_none(*pgd))
-               goto no_pgd;
-       if (pgd_bad(*pgd))
-               goto bad_pgd;
-
-       pmd = pmd_offset(pgd, address);
-       if (pmd_none(*pmd))
-               goto no_pmd;
-       if (pmd_bad(*pmd))
-               goto bad_pmd;
-
-       pte = pte_offset_map(pmd, address);
-       entry = *pte;
-
        /*
         * If this page is present, it's actually being shared.
         */
@@ -68,33 +52,55 @@ static int adjust_pte(struct vm_area_struct *vma, unsigned long address)
         * fault (ie, is old), we can safely ignore any issues.
         */
        if (ret && (pte_val(entry) & L_PTE_MT_MASK) != shared_pte_mask) {
-               unsigned long pfn = pte_pfn(entry);
                flush_cache_page(vma, address, pfn);
                outer_flush_range((pfn << PAGE_SHIFT),
                                  (pfn << PAGE_SHIFT) + PAGE_SIZE);
                pte_val(entry) &= ~L_PTE_MT_MASK;
                pte_val(entry) |= shared_pte_mask;
-               set_pte_at(vma->vm_mm, address, pte, entry);
+               set_pte_at(vma->vm_mm, address, ptep, entry);
                flush_tlb_page(vma, address);
        }
-       pte_unmap(pte);
+
        return ret;
+}
+
+static int adjust_pte(struct vm_area_struct *vma, unsigned long address,
+       unsigned long pfn)
+{
+       spinlock_t *ptl;
+       pgd_t *pgd;
+       pmd_t *pmd;
+       pte_t *pte;
+       int ret;
+
+       pgd = pgd_offset(vma->vm_mm, address);
+       if (pgd_none_or_clear_bad(pgd))
+               return 0;
+
+       pmd = pmd_offset(pgd, address);
+       if (pmd_none_or_clear_bad(pmd))
+               return 0;
 
-bad_pgd:
-       pgd_ERROR(*pgd);
-       pgd_clear(pgd);
-no_pgd:
-       return 0;
-
-bad_pmd:
-       pmd_ERROR(*pmd);
-       pmd_clear(pmd);
-no_pmd:
-       return 0;
+       /*
+        * This is called while another page table is mapped, so we
+        * must use the nested version.  This also means we need to
+        * open-code the spin-locking.
+        */
+       ptl = pte_lockptr(vma->vm_mm, pmd);
+       pte = pte_offset_map_nested(pmd, address);
+       spin_lock(ptl);
+
+       ret = do_adjust_pte(vma, address, pfn, pte);
+
+       spin_unlock(ptl);
+       pte_unmap_nested(pte);
+
+       return ret;
 }
 
 static void
-make_coherent(struct address_space *mapping, struct vm_area_struct *vma, unsigned long addr, unsigned long pfn)
+make_coherent(struct address_space *mapping, struct vm_area_struct *vma,
+       unsigned long addr, pte_t *ptep, unsigned long pfn)
 {
        struct mm_struct *mm = vma->vm_mm;
        struct vm_area_struct *mpnt;
@@ -122,11 +128,11 @@ make_coherent(struct address_space *mapping, struct vm_area_struct *vma, unsigne
                if (!(mpnt->vm_flags & VM_MAYSHARE))
                        continue;
                offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT;
-               aliases += adjust_pte(mpnt, mpnt->vm_start + offset);
+               aliases += adjust_pte(mpnt, mpnt->vm_start + offset, pfn);
        }
        flush_dcache_mmap_unlock(mapping);
        if (aliases)
-               adjust_pte(vma, addr);
+               do_adjust_pte(vma, addr, pfn, ptep);
        else
                flush_cache_page(vma, addr, pfn);
 }
@@ -144,9 +150,10 @@ make_coherent(struct address_space *mapping, struct vm_area_struct *vma, unsigne
  *
  * Note that the pte lock will be held.
  */
-void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte)
+void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr,
+       pte_t *ptep)
 {
-       unsigned long pfn = pte_pfn(pte);
+       unsigned long pfn = pte_pfn(*ptep);
        struct address_space *mapping;
        struct page *page;
 
@@ -168,7 +175,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte)
 #endif
        if (mapping) {
                if (cache_is_vivt())
-                       make_coherent(mapping, vma, addr, pfn);
+                       make_coherent(mapping, vma, addr, ptep, pfn);
                else if (vma->vm_flags & VM_EXEC)
                        __flush_icache_all();
        }
index 10e06801afb38e9d0a60cdb8b8cd94d43bc9e139..9d40c341e07e5846e270934c2b942035cae19f44 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/page-flags.h>
 #include <linux/sched.h>
 #include <linux/highmem.h>
+#include <linux/perf_event.h>
 
 #include <asm/system.h>
 #include <asm/pgtable.h>
@@ -302,6 +303,12 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
        fault = __do_page_fault(mm, addr, fsr, tsk);
        up_read(&mm->mmap_sem);
 
+       perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, addr);
+       if (fault & VM_FAULT_MAJOR)
+               perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0, regs, addr);
+       else if (fault & VM_FAULT_MINOR)
+               perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0, regs, addr);
+
        /*
         * Handle the "normal" case first - VM_FAULT_MAJOR / VM_FAULT_MINOR
         */
index 6f3a4b7a3b8276e5c442e4bbfc8273c8e9745f54..e34f095e2090517b8f968f4af6703e60dd371c8b 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <asm/cacheflush.h>
 #include <asm/cachetype.h>
+#include <asm/smp_plat.h>
 #include <asm/system.h>
 #include <asm/tlbflush.h>
 
@@ -87,13 +88,26 @@ void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsig
        if (vma->vm_flags & VM_EXEC && icache_is_vivt_asid_tagged())
                __flush_icache_all();
 }
+#else
+#define flush_pfn_alias(pfn,vaddr)     do { } while (0)
+#endif
 
+#ifdef CONFIG_SMP
+static void flush_ptrace_access_other(void *args)
+{
+       __flush_icache_all();
+}
+#endif
+
+static
 void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
-                        unsigned long uaddr, void *kaddr,
-                        unsigned long len, int write)
+                        unsigned long uaddr, void *kaddr, unsigned long len)
 {
        if (cache_is_vivt()) {
-               vivt_flush_ptrace_access(vma, page, uaddr, kaddr, len, write);
+               if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) {
+                       unsigned long addr = (unsigned long)kaddr;
+                       __cpuc_coherent_kern_range(addr, addr + len);
+               }
                return;
        }
 
@@ -104,16 +118,37 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
        }
 
        /* VIPT non-aliasing cache */
-       if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm)) &&
-           vma->vm_flags & VM_EXEC) {
+       if (vma->vm_flags & VM_EXEC) {
                unsigned long addr = (unsigned long)kaddr;
-               /* only flushing the kernel mapping on non-aliasing VIPT */
                __cpuc_coherent_kern_range(addr, addr + len);
+#ifdef CONFIG_SMP
+               if (cache_ops_need_broadcast())
+                       smp_call_function(flush_ptrace_access_other,
+                                         NULL, 1);
+#endif
        }
 }
-#else
-#define flush_pfn_alias(pfn,vaddr)     do { } while (0)
+
+/*
+ * Copy user data from/to a page which is mapped into a different
+ * processes address space.  Really, we want to allow our "user
+ * space" model to handle this.
+ *
+ * Note that this code needs to run on the current CPU.
+ */
+void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
+                      unsigned long uaddr, void *dst, const void *src,
+                      unsigned long len)
+{
+#ifdef CONFIG_SMP
+       preempt_disable();
 #endif
+       memcpy(dst, src, len);
+       flush_ptrace_access(vma, page, uaddr, dst, len);
+#ifdef CONFIG_SMP
+       preempt_enable();
+#endif
+}
 
 void __flush_dcache_page(struct address_space *mapping, struct page *page)
 {
index a04ffbbbe2536309ee73442db96fd271a46561a4..7829cb5425f56e460a62390158114db98f4acc10 100644 (file)
@@ -23,6 +23,7 @@
 #include <asm/setup.h>
 #include <asm/sizes.h>
 #include <asm/tlb.h>
+#include <asm/fixmap.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 static unsigned long phys_initrd_start __initdata = 0;
 static unsigned long phys_initrd_size __initdata = 0;
 
-static void __init early_initrd(char **p)
+static int __init early_initrd(char *p)
 {
        unsigned long start, size;
+       char *endp;
 
-       start = memparse(*p, p);
-       if (**p == ',') {
-               size = memparse((*p) + 1, p);
+       start = memparse(p, &endp);
+       if (*endp == ',') {
+               size = memparse(endp + 1, NULL);
 
                phys_initrd_start = start;
                phys_initrd_size = size;
        }
+       return 0;
 }
-__early_param("initrd=", early_initrd);
+early_param("initrd", early_initrd);
 
 static int __init parse_tag_initrd(const struct tag *tag)
 {
@@ -560,7 +563,7 @@ static void __init free_unused_memmap_node(int node, struct meminfo *mi)
  */
 void __init mem_init(void)
 {
-       unsigned int codesize, datasize, initsize;
+       unsigned long reserved_pages, free_pages;
        int i, node;
 
 #ifndef CONFIG_DISCONTIGMEM
@@ -596,6 +599,33 @@ void __init mem_init(void)
        totalram_pages += totalhigh_pages;
 #endif
 
+       reserved_pages = free_pages = 0;
+
+       for_each_online_node(node) {
+               pg_data_t *n = NODE_DATA(node);
+               struct page *map = pgdat_page_nr(n, 0) - n->node_start_pfn;
+
+               for_each_nodebank(i, &meminfo, node) {
+                       struct membank *bank = &meminfo.bank[i];
+                       unsigned int pfn1, pfn2;
+                       struct page *page, *end;
+
+                       pfn1 = bank_pfn_start(bank);
+                       pfn2 = bank_pfn_end(bank);
+
+                       page = map + pfn1;
+                       end  = map + pfn2;
+
+                       do {
+                               if (PageReserved(page))
+                                       reserved_pages++;
+                               else if (!page_count(page))
+                                       free_pages++;
+                               page++;
+                       } while (page < end);
+               }
+       }
+
        /*
         * Since our memory may not be contiguous, calculate the
         * real number of pages we have in this system
@@ -608,16 +638,71 @@ void __init mem_init(void)
        }
        printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT));
 
-       codesize = _etext - _text;
-       datasize = _end - _data;
-       initsize = __init_end - __init_begin;
-
-       printk(KERN_NOTICE "Memory: %luKB available (%dK code, "
-               "%dK data, %dK init, %luK highmem)\n",
-               nr_free_pages() << (PAGE_SHIFT-10), codesize >> 10,
-               datasize >> 10, initsize >> 10,
+       printk(KERN_NOTICE "Memory: %luk/%luk available, %luk reserved, %luK highmem\n",
+               nr_free_pages() << (PAGE_SHIFT-10),
+               free_pages << (PAGE_SHIFT-10),
+               reserved_pages << (PAGE_SHIFT-10),
                totalhigh_pages << (PAGE_SHIFT-10));
 
+#define MLK(b, t) b, t, ((t) - (b)) >> 10
+#define MLM(b, t) b, t, ((t) - (b)) >> 20
+#define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K)
+
+       printk(KERN_NOTICE "Virtual kernel memory layout:\n"
+                       "    vector  : 0x%08lx - 0x%08lx   (%4ld kB)\n"
+                       "    fixmap  : 0x%08lx - 0x%08lx   (%4ld kB)\n"
+#ifdef CONFIG_MMU
+                       "    DMA     : 0x%08lx - 0x%08lx   (%4ld MB)\n"
+#endif
+                       "    vmalloc : 0x%08lx - 0x%08lx   (%4ld MB)\n"
+                       "    lowmem  : 0x%08lx - 0x%08lx   (%4ld MB)\n"
+#ifdef CONFIG_HIGHMEM
+                       "    pkmap   : 0x%08lx - 0x%08lx   (%4ld MB)\n"
+#endif
+                       "    modules : 0x%08lx - 0x%08lx   (%4ld MB)\n"
+                       "      .init : 0x%p" " - 0x%p" "   (%4d kB)\n"
+                       "      .text : 0x%p" " - 0x%p" "   (%4d kB)\n"
+                       "      .data : 0x%p" " - 0x%p" "   (%4d kB)\n",
+
+                       MLK(UL(CONFIG_VECTORS_BASE), UL(CONFIG_VECTORS_BASE) +
+                               (PAGE_SIZE)),
+                       MLK(FIXADDR_START, FIXADDR_TOP),
+#ifdef CONFIG_MMU
+                       MLM(CONSISTENT_BASE, CONSISTENT_END),
+#endif
+                       MLM(VMALLOC_START, VMALLOC_END),
+                       MLM(PAGE_OFFSET, (unsigned long)high_memory),
+#ifdef CONFIG_HIGHMEM
+                       MLM(PKMAP_BASE, (PKMAP_BASE) + (LAST_PKMAP) *
+                               (PAGE_SIZE)),
+#endif
+                       MLM(MODULES_VADDR, MODULES_END),
+
+                       MLK_ROUNDUP(__init_begin, __init_end),
+                       MLK_ROUNDUP(_text, _etext),
+                       MLK_ROUNDUP(_data, _edata));
+
+#undef MLK
+#undef MLM
+#undef MLK_ROUNDUP
+
+       /*
+        * Check boundaries twice: Some fundamental inconsistencies can
+        * be detected at build time already.
+        */
+#ifdef CONFIG_MMU
+       BUILD_BUG_ON(VMALLOC_END                        > CONSISTENT_BASE);
+       BUG_ON(VMALLOC_END                              > CONSISTENT_BASE);
+
+       BUILD_BUG_ON(TASK_SIZE                          > MODULES_VADDR);
+       BUG_ON(TASK_SIZE                                > MODULES_VADDR);
+#endif
+
+#ifdef CONFIG_HIGHMEM
+       BUILD_BUG_ON(PKMAP_BASE + LAST_PKMAP * PAGE_SIZE > PAGE_OFFSET);
+       BUG_ON(PKMAP_BASE + LAST_PKMAP * PAGE_SIZE      > PAGE_OFFSET);
+#endif
+
        if (PAGE_SIZE >= 16384 && num_physpages <= 128) {
                extern int sysctl_overcommit_memory;
                /*
index 0ab75c60f7cfdf4745cc1f9c48d87db61cb93918..28c8b950ef04e84f6d0893712fb22c5394808ee6 100644 (file)
@@ -139,8 +139,8 @@ void __check_kvm_seq(struct mm_struct *mm)
  * which requires the new ioremap'd region to be referenced, the CPU will
  * reference the _old_ region.
  *
- * Note that get_vm_area() allocates a guard 4K page, so we need to mask
- * the size back to 1MB aligned or we will overflow in the loop below.
+ * Note that get_vm_area_caller() allocates a guard 4K page, so we need to
+ * mask the size back to 1MB aligned or we will overflow in the loop below.
  */
 static void unmap_area_sections(unsigned long virt, unsigned long size)
 {
@@ -254,22 +254,8 @@ remap_area_supersections(unsigned long virt, unsigned long pfn,
 }
 #endif
 
-
-/*
- * Remap an arbitrary physical address space into the kernel virtual
- * address space. Needed when the kernel wants to access high addresses
- * directly.
- *
- * NOTE! We need to allow non-page-aligned mappings too: we will obviously
- * have to convert them into an offset in a page-aligned mapping, but the
- * caller shouldn't need to know that small detail.
- *
- * 'flags' are the extra L_PTE_ flags that you want to specify for this
- * mapping.  See <asm/pgtable.h> for more information.
- */
-void __iomem *
-__arm_ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size,
-                 unsigned int mtype)
+void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn,
+       unsigned long offset, size_t size, unsigned int mtype, void *caller)
 {
        const struct mem_type *type;
        int err;
@@ -291,7 +277,7 @@ __arm_ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size,
         */
        size = PAGE_ALIGN(offset + size);
 
-       area = get_vm_area(size, VM_IOREMAP);
+       area = get_vm_area_caller(size, VM_IOREMAP, caller);
        if (!area)
                return NULL;
        addr = (unsigned long)area->addr;
@@ -318,10 +304,9 @@ __arm_ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size,
        flush_cache_vmap(addr, addr + size);
        return (void __iomem *) (offset + addr);
 }
-EXPORT_SYMBOL(__arm_ioremap_pfn);
 
-void __iomem *
-__arm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
+void __iomem *__arm_ioremap_caller(unsigned long phys_addr, size_t size,
+       unsigned int mtype, void *caller)
 {
        unsigned long last_addr;
        unsigned long offset = phys_addr & ~PAGE_MASK;
@@ -334,7 +319,33 @@ __arm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
        if (!size || last_addr < phys_addr)
                return NULL;
 
-       return __arm_ioremap_pfn(pfn, offset, size, mtype);
+       return __arm_ioremap_pfn_caller(pfn, offset, size, mtype,
+                       caller);
+}
+
+/*
+ * Remap an arbitrary physical address space into the kernel virtual
+ * address space. Needed when the kernel wants to access high addresses
+ * directly.
+ *
+ * NOTE! We need to allow non-page-aligned mappings too: we will obviously
+ * have to convert them into an offset in a page-aligned mapping, but the
+ * caller shouldn't need to know that small detail.
+ */
+void __iomem *
+__arm_ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size,
+                 unsigned int mtype)
+{
+       return __arm_ioremap_pfn_caller(pfn, offset, size, mtype,
+                       __builtin_return_address(0));
+}
+EXPORT_SYMBOL(__arm_ioremap_pfn);
+
+void __iomem *
+__arm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
+{
+       return __arm_ioremap_caller(phys_addr, size, mtype,
+                       __builtin_return_address(0));
 }
 EXPORT_SYMBOL(__arm_ioremap);
 
index 761ffede6a23a9027bd6d805a7fdb8d5e674c7ec..9d4da6ac28ebf9fae8718de70af211beede72156 100644 (file)
@@ -100,18 +100,17 @@ static struct cachepolicy cache_policies[] __initdata = {
  * writebuffer to be turned off.  (Note: the write
  * buffer should not be on and the cache off).
  */
-static void __init early_cachepolicy(char **p)
+static int __init early_cachepolicy(char *p)
 {
        int i;
 
        for (i = 0; i < ARRAY_SIZE(cache_policies); i++) {
                int len = strlen(cache_policies[i].policy);
 
-               if (memcmp(*p, cache_policies[i].policy, len) == 0) {
+               if (memcmp(p, cache_policies[i].policy, len) == 0) {
                        cachepolicy = i;
                        cr_alignment &= ~cache_policies[i].cr_mask;
                        cr_no_alignment &= ~cache_policies[i].cr_mask;
-                       *p += len;
                        break;
                }
        }
@@ -130,36 +129,37 @@ static void __init early_cachepolicy(char **p)
        }
        flush_cache_all();
        set_cr(cr_alignment);
+       return 0;
 }
-__early_param("cachepolicy=", early_cachepolicy);
+early_param("cachepolicy", early_cachepolicy);
 
-static void __init early_nocache(char **__unused)
+static int __init early_nocache(char *__unused)
 {
        char *p = "buffered";
        printk(KERN_WARNING "nocache is deprecated; use cachepolicy=%s\n", p);
-       early_cachepolicy(&p);
+       early_cachepolicy(p);
+       return 0;
 }
-__early_param("nocache", early_nocache);
+early_param("nocache", early_nocache);
 
-static void __init early_nowrite(char **__unused)
+static int __init early_nowrite(char *__unused)
 {
        char *p = "uncached";
        printk(KERN_WARNING "nowb is deprecated; use cachepolicy=%s\n", p);
-       early_cachepolicy(&p);
+       early_cachepolicy(p);
+       return 0;
 }
-__early_param("nowb", early_nowrite);
+early_param("nowb", early_nowrite);
 
-static void __init early_ecc(char **p)
+static int __init early_ecc(char *p)
 {
-       if (memcmp(*p, "on", 2) == 0) {
+       if (memcmp(p, "on", 2) == 0)
                ecc_mask = PMD_PROTECTION;
-               *p += 2;
-       } else if (memcmp(*p, "off", 3) == 0) {
+       else if (memcmp(p, "off", 3) == 0)
                ecc_mask = 0;
-               *p += 3;
-       }
+       return 0;
 }
-__early_param("ecc=", early_ecc);
+early_param("ecc", early_ecc);
 
 static int __init noalign_setup(char *__unused)
 {
@@ -670,9 +670,9 @@ static unsigned long __initdata vmalloc_reserve = SZ_128M;
  * bytes. This can be used to increase (or decrease) the vmalloc
  * area - the default is 128m.
  */
-static void __init early_vmalloc(char **arg)
+static int __init early_vmalloc(char *arg)
 {
-       vmalloc_reserve = memparse(*arg, arg);
+       vmalloc_reserve = memparse(arg, NULL);
 
        if (vmalloc_reserve < SZ_16M) {
                vmalloc_reserve = SZ_16M;
@@ -687,8 +687,9 @@ static void __init early_vmalloc(char **arg)
                        "vmalloc area is too big, limiting to %luMB\n",
                        vmalloc_reserve >> 20);
        }
+       return 0;
 }
-__early_param("vmalloc=", early_vmalloc);
+early_param("vmalloc", early_vmalloc);
 
 #define VMALLOC_MIN    (void *)(VMALLOC_END - vmalloc_reserve)
 
index 374a8311bc84b0eeadaa37a14004ee53f499ab67..9bfeb6b9509ad3480bd33a664e51b4f94311bfbb 100644 (file)
@@ -74,6 +74,12 @@ void __iomem *__arm_ioremap_pfn(unsigned long pfn, unsigned long offset,
 }
 EXPORT_SYMBOL(__arm_ioremap_pfn);
 
+void __iomem *__arm_ioremap_pfn_caller(unsigned long pfn, unsigned long offset,
+                          size_t size, unsigned int mtype, void *caller)
+{
+       return __arm_ioremap_pfn(pfn, offset, size, mtype);
+}
+
 void __iomem *__arm_ioremap(unsigned long phys_addr, size_t size,
                            unsigned int mtype)
 {
@@ -81,6 +87,12 @@ void __iomem *__arm_ioremap(unsigned long phys_addr, size_t size,
 }
 EXPORT_SYMBOL(__arm_ioremap);
 
+void __iomem *__arm_ioremap(unsigned long phys_addr, size_t size,
+                           unsigned int mtype, void *caller)
+{
+       return __arm_ioremap(phys_addr, size, mtype);
+}
+
 void __iounmap(volatile void __iomem *addr)
 {
 }
index 8012e24282b2d0ffbbab5a38cd963c6cb9acf6e5..72507c630ceb563e9242145722b542b52731a7b3 100644 (file)
@@ -265,7 +265,7 @@ ENTRY(arm1020_flush_kern_dcache_area)
  *
  * (same as v4wb)
  */
-ENTRY(arm1020_dma_inv_range)
+arm1020_dma_inv_range:
        mov     ip, #0
 #ifndef CONFIG_CPU_DCACHE_DISABLE
        tst     r0, #CACHE_DLINESIZE - 1
@@ -295,7 +295,7 @@ ENTRY(arm1020_dma_inv_range)
  *
  * (same as v4wb)
  */
-ENTRY(arm1020_dma_clean_range)
+arm1020_dma_clean_range:
        mov     ip, #0
 #ifndef CONFIG_CPU_DCACHE_DISABLE
        bic     r0, r0, #CACHE_DLINESIZE - 1
@@ -330,6 +330,30 @@ ENTRY(arm1020_dma_flush_range)
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
        mov     pc, lr
 
+/*
+ *     dma_map_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(arm1020_dma_map_area)
+       add     r1, r1, r0
+       cmp     r2, #DMA_TO_DEVICE
+       beq     arm1020_dma_clean_range
+       bcs     arm1020_dma_inv_range
+       b       arm1020_dma_flush_range
+ENDPROC(arm1020_dma_map_area)
+
+/*
+ *     dma_unmap_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(arm1020_dma_unmap_area)
+       mov     pc, lr
+ENDPROC(arm1020_dma_unmap_area)
+
 ENTRY(arm1020_cache_fns)
        .long   arm1020_flush_kern_cache_all
        .long   arm1020_flush_user_cache_all
@@ -337,8 +361,8 @@ ENTRY(arm1020_cache_fns)
        .long   arm1020_coherent_kern_range
        .long   arm1020_coherent_user_range
        .long   arm1020_flush_kern_dcache_area
-       .long   arm1020_dma_inv_range
-       .long   arm1020_dma_clean_range
+       .long   arm1020_dma_map_area
+       .long   arm1020_dma_unmap_area
        .long   arm1020_dma_flush_range
 
        .align  5
index 41fe25d234f50b76b563c6b5516a258d45c014fe..d27829805609f5793e23bb2fd0c67ac85993e955 100644 (file)
@@ -258,7 +258,7 @@ ENTRY(arm1020e_flush_kern_dcache_area)
  *
  * (same as v4wb)
  */
-ENTRY(arm1020e_dma_inv_range)
+arm1020e_dma_inv_range:
        mov     ip, #0
 #ifndef CONFIG_CPU_DCACHE_DISABLE
        tst     r0, #CACHE_DLINESIZE - 1
@@ -284,7 +284,7 @@ ENTRY(arm1020e_dma_inv_range)
  *
  * (same as v4wb)
  */
-ENTRY(arm1020e_dma_clean_range)
+arm1020e_dma_clean_range:
        mov     ip, #0
 #ifndef CONFIG_CPU_DCACHE_DISABLE
        bic     r0, r0, #CACHE_DLINESIZE - 1
@@ -316,6 +316,30 @@ ENTRY(arm1020e_dma_flush_range)
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
        mov     pc, lr
 
+/*
+ *     dma_map_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(arm1020e_dma_map_area)
+       add     r1, r1, r0
+       cmp     r2, #DMA_TO_DEVICE
+       beq     arm1020e_dma_clean_range
+       bcs     arm1020e_dma_inv_range
+       b       arm1020e_dma_flush_range
+ENDPROC(arm1020e_dma_map_area)
+
+/*
+ *     dma_unmap_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(arm1020e_dma_unmap_area)
+       mov     pc, lr
+ENDPROC(arm1020e_dma_unmap_area)
+
 ENTRY(arm1020e_cache_fns)
        .long   arm1020e_flush_kern_cache_all
        .long   arm1020e_flush_user_cache_all
@@ -323,8 +347,8 @@ ENTRY(arm1020e_cache_fns)
        .long   arm1020e_coherent_kern_range
        .long   arm1020e_coherent_user_range
        .long   arm1020e_flush_kern_dcache_area
-       .long   arm1020e_dma_inv_range
-       .long   arm1020e_dma_clean_range
+       .long   arm1020e_dma_map_area
+       .long   arm1020e_dma_unmap_area
        .long   arm1020e_dma_flush_range
 
        .align  5
index 20a5b1b31a706051ac2c1b6cb58b293b3b2794a2..ce13e4a827de8ed9e787b11bf3a784b0bf803dab 100644 (file)
@@ -247,7 +247,7 @@ ENTRY(arm1022_flush_kern_dcache_area)
  *
  * (same as v4wb)
  */
-ENTRY(arm1022_dma_inv_range)
+arm1022_dma_inv_range:
        mov     ip, #0
 #ifndef CONFIG_CPU_DCACHE_DISABLE
        tst     r0, #CACHE_DLINESIZE - 1
@@ -273,7 +273,7 @@ ENTRY(arm1022_dma_inv_range)
  *
  * (same as v4wb)
  */
-ENTRY(arm1022_dma_clean_range)
+arm1022_dma_clean_range:
        mov     ip, #0
 #ifndef CONFIG_CPU_DCACHE_DISABLE
        bic     r0, r0, #CACHE_DLINESIZE - 1
@@ -305,6 +305,30 @@ ENTRY(arm1022_dma_flush_range)
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
        mov     pc, lr
 
+/*
+ *     dma_map_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(arm1022_dma_map_area)
+       add     r1, r1, r0
+       cmp     r2, #DMA_TO_DEVICE
+       beq     arm1022_dma_clean_range
+       bcs     arm1022_dma_inv_range
+       b       arm1022_dma_flush_range
+ENDPROC(arm1022_dma_map_area)
+
+/*
+ *     dma_unmap_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(arm1022_dma_unmap_area)
+       mov     pc, lr
+ENDPROC(arm1022_dma_unmap_area)
+
 ENTRY(arm1022_cache_fns)
        .long   arm1022_flush_kern_cache_all
        .long   arm1022_flush_user_cache_all
@@ -312,8 +336,8 @@ ENTRY(arm1022_cache_fns)
        .long   arm1022_coherent_kern_range
        .long   arm1022_coherent_user_range
        .long   arm1022_flush_kern_dcache_area
-       .long   arm1022_dma_inv_range
-       .long   arm1022_dma_clean_range
+       .long   arm1022_dma_map_area
+       .long   arm1022_dma_unmap_area
        .long   arm1022_dma_flush_range
 
        .align  5
index 96aedb10fcc418c528f536fb9a06f77185a3fa9c..636672a29c6d1e58ad905850cba7374ba09d8f45 100644 (file)
@@ -241,7 +241,7 @@ ENTRY(arm1026_flush_kern_dcache_area)
  *
  * (same as v4wb)
  */
-ENTRY(arm1026_dma_inv_range)
+arm1026_dma_inv_range:
        mov     ip, #0
 #ifndef CONFIG_CPU_DCACHE_DISABLE
        tst     r0, #CACHE_DLINESIZE - 1
@@ -267,7 +267,7 @@ ENTRY(arm1026_dma_inv_range)
  *
  * (same as v4wb)
  */
-ENTRY(arm1026_dma_clean_range)
+arm1026_dma_clean_range:
        mov     ip, #0
 #ifndef CONFIG_CPU_DCACHE_DISABLE
        bic     r0, r0, #CACHE_DLINESIZE - 1
@@ -299,6 +299,30 @@ ENTRY(arm1026_dma_flush_range)
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
        mov     pc, lr
 
+/*
+ *     dma_map_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(arm1026_dma_map_area)
+       add     r1, r1, r0
+       cmp     r2, #DMA_TO_DEVICE
+       beq     arm1026_dma_clean_range
+       bcs     arm1026_dma_inv_range
+       b       arm1026_dma_flush_range
+ENDPROC(arm1026_dma_map_area)
+
+/*
+ *     dma_unmap_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(arm1026_dma_unmap_area)
+       mov     pc, lr
+ENDPROC(arm1026_dma_unmap_area)
+
 ENTRY(arm1026_cache_fns)
        .long   arm1026_flush_kern_cache_all
        .long   arm1026_flush_user_cache_all
@@ -306,8 +330,8 @@ ENTRY(arm1026_cache_fns)
        .long   arm1026_coherent_kern_range
        .long   arm1026_coherent_user_range
        .long   arm1026_flush_kern_dcache_area
-       .long   arm1026_dma_inv_range
-       .long   arm1026_dma_clean_range
+       .long   arm1026_dma_map_area
+       .long   arm1026_dma_unmap_area
        .long   arm1026_dma_flush_range
 
        .align  5
index 471669e2d7cb458567d9233a805dd8ce772bf719..8be81992645d8d814517510ea473d85c604888bd 100644 (file)
@@ -239,7 +239,7 @@ ENTRY(arm920_flush_kern_dcache_area)
  *
  * (same as v4wb)
  */
-ENTRY(arm920_dma_inv_range)
+arm920_dma_inv_range:
        tst     r0, #CACHE_DLINESIZE - 1
        bic     r0, r0, #CACHE_DLINESIZE - 1
        mcrne   p15, 0, r0, c7, c10, 1          @ clean D entry
@@ -262,7 +262,7 @@ ENTRY(arm920_dma_inv_range)
  *
  * (same as v4wb)
  */
-ENTRY(arm920_dma_clean_range)
+arm920_dma_clean_range:
        bic     r0, r0, #CACHE_DLINESIZE - 1
 1:     mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
        add     r0, r0, #CACHE_DLINESIZE
@@ -288,6 +288,30 @@ ENTRY(arm920_dma_flush_range)
        mcr     p15, 0, r0, c7, c10, 4          @ drain WB
        mov     pc, lr
 
+/*
+ *     dma_map_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(arm920_dma_map_area)
+       add     r1, r1, r0
+       cmp     r2, #DMA_TO_DEVICE
+       beq     arm920_dma_clean_range
+       bcs     arm920_dma_inv_range
+       b       arm920_dma_flush_range
+ENDPROC(arm920_dma_map_area)
+
+/*
+ *     dma_unmap_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(arm920_dma_unmap_area)
+       mov     pc, lr
+ENDPROC(arm920_dma_unmap_area)
+
 ENTRY(arm920_cache_fns)
        .long   arm920_flush_kern_cache_all
        .long   arm920_flush_user_cache_all
@@ -295,8 +319,8 @@ ENTRY(arm920_cache_fns)
        .long   arm920_coherent_kern_range
        .long   arm920_coherent_user_range
        .long   arm920_flush_kern_dcache_area
-       .long   arm920_dma_inv_range
-       .long   arm920_dma_clean_range
+       .long   arm920_dma_map_area
+       .long   arm920_dma_unmap_area
        .long   arm920_dma_flush_range
 
 #endif
index ee111b00fa41951619593c758fe22eb06a4e4ee4..c0ff8e4b1074bac560f318a25c2715b89976c603 100644 (file)
@@ -241,7 +241,7 @@ ENTRY(arm922_flush_kern_dcache_area)
  *
  * (same as v4wb)
  */
-ENTRY(arm922_dma_inv_range)
+arm922_dma_inv_range:
        tst     r0, #CACHE_DLINESIZE - 1
        bic     r0, r0, #CACHE_DLINESIZE - 1
        mcrne   p15, 0, r0, c7, c10, 1          @ clean D entry
@@ -264,7 +264,7 @@ ENTRY(arm922_dma_inv_range)
  *
  * (same as v4wb)
  */
-ENTRY(arm922_dma_clean_range)
+arm922_dma_clean_range:
        bic     r0, r0, #CACHE_DLINESIZE - 1
 1:     mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
        add     r0, r0, #CACHE_DLINESIZE
@@ -290,6 +290,30 @@ ENTRY(arm922_dma_flush_range)
        mcr     p15, 0, r0, c7, c10, 4          @ drain WB
        mov     pc, lr
 
+/*
+ *     dma_map_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(arm922_dma_map_area)
+       add     r1, r1, r0
+       cmp     r2, #DMA_TO_DEVICE
+       beq     arm922_dma_clean_range
+       bcs     arm922_dma_inv_range
+       b       arm922_dma_flush_range
+ENDPROC(arm922_dma_map_area)
+
+/*
+ *     dma_unmap_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(arm922_dma_unmap_area)
+       mov     pc, lr
+ENDPROC(arm922_dma_unmap_area)
+
 ENTRY(arm922_cache_fns)
        .long   arm922_flush_kern_cache_all
        .long   arm922_flush_user_cache_all
@@ -297,8 +321,8 @@ ENTRY(arm922_cache_fns)
        .long   arm922_coherent_kern_range
        .long   arm922_coherent_user_range
        .long   arm922_flush_kern_dcache_area
-       .long   arm922_dma_inv_range
-       .long   arm922_dma_clean_range
+       .long   arm922_dma_map_area
+       .long   arm922_dma_unmap_area
        .long   arm922_dma_flush_range
 
 #endif
index 8deb5bde58e4883765e1d7bb6b81b10e0388911b..3c6cffe400f685f4dc3e32ccf078ef726d88d625 100644 (file)
@@ -283,7 +283,7 @@ ENTRY(arm925_flush_kern_dcache_area)
  *
  * (same as v4wb)
  */
-ENTRY(arm925_dma_inv_range)
+arm925_dma_inv_range:
 #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
        tst     r0, #CACHE_DLINESIZE - 1
        mcrne   p15, 0, r0, c7, c10, 1          @ clean D entry
@@ -308,7 +308,7 @@ ENTRY(arm925_dma_inv_range)
  *
  * (same as v4wb)
  */
-ENTRY(arm925_dma_clean_range)
+arm925_dma_clean_range:
 #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
        bic     r0, r0, #CACHE_DLINESIZE - 1
 1:     mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
@@ -341,6 +341,30 @@ ENTRY(arm925_dma_flush_range)
        mcr     p15, 0, r0, c7, c10, 4          @ drain WB
        mov     pc, lr
 
+/*
+ *     dma_map_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(arm925_dma_map_area)
+       add     r1, r1, r0
+       cmp     r2, #DMA_TO_DEVICE
+       beq     arm925_dma_clean_range
+       bcs     arm925_dma_inv_range
+       b       arm925_dma_flush_range
+ENDPROC(arm925_dma_map_area)
+
+/*
+ *     dma_unmap_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(arm925_dma_unmap_area)
+       mov     pc, lr
+ENDPROC(arm925_dma_unmap_area)
+
 ENTRY(arm925_cache_fns)
        .long   arm925_flush_kern_cache_all
        .long   arm925_flush_user_cache_all
@@ -348,8 +372,8 @@ ENTRY(arm925_cache_fns)
        .long   arm925_coherent_kern_range
        .long   arm925_coherent_user_range
        .long   arm925_flush_kern_dcache_area
-       .long   arm925_dma_inv_range
-       .long   arm925_dma_clean_range
+       .long   arm925_dma_map_area
+       .long   arm925_dma_unmap_area
        .long   arm925_dma_flush_range
 
 ENTRY(cpu_arm925_dcache_clean_area)
index 64db6e275a442f610239fe9b692753c4d88d14f9..75b707c9cce1ad31c2adf960d99e99cb5a266f8d 100644 (file)
@@ -246,7 +246,7 @@ ENTRY(arm926_flush_kern_dcache_area)
  *
  * (same as v4wb)
  */
-ENTRY(arm926_dma_inv_range)
+arm926_dma_inv_range:
 #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
        tst     r0, #CACHE_DLINESIZE - 1
        mcrne   p15, 0, r0, c7, c10, 1          @ clean D entry
@@ -271,7 +271,7 @@ ENTRY(arm926_dma_inv_range)
  *
  * (same as v4wb)
  */
-ENTRY(arm926_dma_clean_range)
+arm926_dma_clean_range:
 #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
        bic     r0, r0, #CACHE_DLINESIZE - 1
 1:     mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
@@ -304,6 +304,30 @@ ENTRY(arm926_dma_flush_range)
        mcr     p15, 0, r0, c7, c10, 4          @ drain WB
        mov     pc, lr
 
+/*
+ *     dma_map_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(arm926_dma_map_area)
+       add     r1, r1, r0
+       cmp     r2, #DMA_TO_DEVICE
+       beq     arm926_dma_clean_range
+       bcs     arm926_dma_inv_range
+       b       arm926_dma_flush_range
+ENDPROC(arm926_dma_map_area)
+
+/*
+ *     dma_unmap_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(arm926_dma_unmap_area)
+       mov     pc, lr
+ENDPROC(arm926_dma_unmap_area)
+
 ENTRY(arm926_cache_fns)
        .long   arm926_flush_kern_cache_all
        .long   arm926_flush_user_cache_all
@@ -311,8 +335,8 @@ ENTRY(arm926_cache_fns)
        .long   arm926_coherent_kern_range
        .long   arm926_coherent_user_range
        .long   arm926_flush_kern_dcache_area
-       .long   arm926_dma_inv_range
-       .long   arm926_dma_clean_range
+       .long   arm926_dma_map_area
+       .long   arm926_dma_unmap_area
        .long   arm926_dma_flush_range
 
 ENTRY(cpu_arm926_dcache_clean_area)
index 8196b9f401fb53f17cd0a215c384a872330e054d..1af1657819eb8e32caf40dbbc148ca2c0259144f 100644 (file)
@@ -171,7 +171,7 @@ ENTRY(arm940_flush_kern_dcache_area)
  *     - start - virtual start address
  *     - end   - virtual end address
  */
-ENTRY(arm940_dma_inv_range)
+arm940_dma_inv_range:
        mov     ip, #0
        mov     r1, #(CACHE_DSEGMENTS - 1) << 4 @ 4 segments
 1:     orr     r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries
@@ -192,7 +192,7 @@ ENTRY(arm940_dma_inv_range)
  *     - start - virtual start address
  *     - end   - virtual end address
  */
-ENTRY(arm940_dma_clean_range)
+arm940_dma_clean_range:
 ENTRY(cpu_arm940_dcache_clean_area)
        mov     ip, #0
 #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
@@ -233,6 +233,30 @@ ENTRY(arm940_dma_flush_range)
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
        mov     pc, lr
 
+/*
+ *     dma_map_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(arm940_dma_map_area)
+       add     r1, r1, r0
+       cmp     r2, #DMA_TO_DEVICE
+       beq     arm940_dma_clean_range
+       bcs     arm940_dma_inv_range
+       b       arm940_dma_flush_range
+ENDPROC(arm940_dma_map_area)
+
+/*
+ *     dma_unmap_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(arm940_dma_unmap_area)
+       mov     pc, lr
+ENDPROC(arm940_dma_unmap_area)
+
 ENTRY(arm940_cache_fns)
        .long   arm940_flush_kern_cache_all
        .long   arm940_flush_user_cache_all
@@ -240,8 +264,8 @@ ENTRY(arm940_cache_fns)
        .long   arm940_coherent_kern_range
        .long   arm940_coherent_user_range
        .long   arm940_flush_kern_dcache_area
-       .long   arm940_dma_inv_range
-       .long   arm940_dma_clean_range
+       .long   arm940_dma_map_area
+       .long   arm940_dma_unmap_area
        .long   arm940_dma_flush_range
 
        __INIT
index 9a951239c86c0a1b93dcefdf6687312b6c3c51c7..1664b6aaff794957723cfac21696e8a2af030f3b 100644 (file)
@@ -215,7 +215,7 @@ ENTRY(arm946_flush_kern_dcache_area)
  *     - end   - virtual end address
  * (same as arm926)
  */
-ENTRY(arm946_dma_inv_range)
+arm946_dma_inv_range:
 #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
        tst     r0, #CACHE_DLINESIZE - 1
        mcrne   p15, 0, r0, c7, c10, 1          @ clean D entry
@@ -240,7 +240,7 @@ ENTRY(arm946_dma_inv_range)
  *
  * (same as arm926)
  */
-ENTRY(arm946_dma_clean_range)
+arm946_dma_clean_range:
 #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
        bic     r0, r0, #CACHE_DLINESIZE - 1
 1:     mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
@@ -275,6 +275,30 @@ ENTRY(arm946_dma_flush_range)
        mcr     p15, 0, r0, c7, c10, 4          @ drain WB
        mov     pc, lr
 
+/*
+ *     dma_map_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(arm946_dma_map_area)
+       add     r1, r1, r0
+       cmp     r2, #DMA_TO_DEVICE
+       beq     arm946_dma_clean_range
+       bcs     arm946_dma_inv_range
+       b       arm946_dma_flush_range
+ENDPROC(arm946_dma_map_area)
+
+/*
+ *     dma_unmap_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(arm946_dma_unmap_area)
+       mov     pc, lr
+ENDPROC(arm946_dma_unmap_area)
+
 ENTRY(arm946_cache_fns)
        .long   arm946_flush_kern_cache_all
        .long   arm946_flush_user_cache_all
@@ -282,8 +306,8 @@ ENTRY(arm946_cache_fns)
        .long   arm946_coherent_kern_range
        .long   arm946_coherent_user_range
        .long   arm946_flush_kern_dcache_area
-       .long   arm946_dma_inv_range
-       .long   arm946_dma_clean_range
+       .long   arm946_dma_map_area
+       .long   arm946_dma_unmap_area
        .long   arm946_dma_flush_range
 
 
index dbc39383e66aaf0d2ec0e5865f15e21dafb02ec7..53e63234384992ed07daf2eb48da91eaa5fa4a7d 100644 (file)
@@ -274,7 +274,7 @@ ENTRY(feroceon_range_flush_kern_dcache_area)
  * (same as v4wb)
  */
        .align  5
-ENTRY(feroceon_dma_inv_range)
+feroceon_dma_inv_range:
        tst     r0, #CACHE_DLINESIZE - 1
        bic     r0, r0, #CACHE_DLINESIZE - 1
        mcrne   p15, 0, r0, c7, c10, 1          @ clean D entry
@@ -288,7 +288,7 @@ ENTRY(feroceon_dma_inv_range)
        mov     pc, lr
 
        .align  5
-ENTRY(feroceon_range_dma_inv_range)
+feroceon_range_dma_inv_range:
        mrs     r2, cpsr
        tst     r0, #CACHE_DLINESIZE - 1
        mcrne   p15, 0, r0, c7, c10, 1          @ clean D entry
@@ -314,7 +314,7 @@ ENTRY(feroceon_range_dma_inv_range)
  * (same as v4wb)
  */
        .align  5
-ENTRY(feroceon_dma_clean_range)
+feroceon_dma_clean_range:
        bic     r0, r0, #CACHE_DLINESIZE - 1
 1:     mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
        add     r0, r0, #CACHE_DLINESIZE
@@ -324,7 +324,7 @@ ENTRY(feroceon_dma_clean_range)
        mov     pc, lr
 
        .align  5
-ENTRY(feroceon_range_dma_clean_range)
+feroceon_range_dma_clean_range:
        mrs     r2, cpsr
        cmp     r1, r0
        subne   r1, r1, #1                      @ top address is inclusive
@@ -367,6 +367,44 @@ ENTRY(feroceon_range_dma_flush_range)
        mcr     p15, 0, r0, c7, c10, 4          @ drain WB
        mov     pc, lr
 
+/*
+ *     dma_map_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(feroceon_dma_map_area)
+       add     r1, r1, r0
+       cmp     r2, #DMA_TO_DEVICE
+       beq     feroceon_dma_clean_range
+       bcs     feroceon_dma_inv_range
+       b       feroceon_dma_flush_range
+ENDPROC(feroceon_dma_map_area)
+
+/*
+ *     dma_map_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(feroceon_range_dma_map_area)
+       add     r1, r1, r0
+       cmp     r2, #DMA_TO_DEVICE
+       beq     feroceon_range_dma_clean_range
+       bcs     feroceon_range_dma_inv_range
+       b       feroceon_range_dma_flush_range
+ENDPROC(feroceon_range_dma_map_area)
+
+/*
+ *     dma_unmap_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(feroceon_dma_unmap_area)
+       mov     pc, lr
+ENDPROC(feroceon_dma_unmap_area)
+
 ENTRY(feroceon_cache_fns)
        .long   feroceon_flush_kern_cache_all
        .long   feroceon_flush_user_cache_all
@@ -374,8 +412,8 @@ ENTRY(feroceon_cache_fns)
        .long   feroceon_coherent_kern_range
        .long   feroceon_coherent_user_range
        .long   feroceon_flush_kern_dcache_area
-       .long   feroceon_dma_inv_range
-       .long   feroceon_dma_clean_range
+       .long   feroceon_dma_map_area
+       .long   feroceon_dma_unmap_area
        .long   feroceon_dma_flush_range
 
 ENTRY(feroceon_range_cache_fns)
@@ -385,8 +423,8 @@ ENTRY(feroceon_range_cache_fns)
        .long   feroceon_coherent_kern_range
        .long   feroceon_coherent_user_range
        .long   feroceon_range_flush_kern_dcache_area
-       .long   feroceon_range_dma_inv_range
-       .long   feroceon_range_dma_clean_range
+       .long   feroceon_range_dma_map_area
+       .long   feroceon_dma_unmap_area
        .long   feroceon_range_dma_flush_range
 
        .align  5
index 9674d36cc97d4c1a6489599d2047b3c29ef58110..caa31154e7dbf71417beebc71128e0d061fb17ce 100644 (file)
@@ -218,7 +218,7 @@ ENTRY(mohawk_flush_kern_dcache_area)
  *
  * (same as v4wb)
  */
-ENTRY(mohawk_dma_inv_range)
+mohawk_dma_inv_range:
        tst     r0, #CACHE_DLINESIZE - 1
        mcrne   p15, 0, r0, c7, c10, 1          @ clean D entry
        tst     r1, #CACHE_DLINESIZE - 1
@@ -241,7 +241,7 @@ ENTRY(mohawk_dma_inv_range)
  *
  * (same as v4wb)
  */
-ENTRY(mohawk_dma_clean_range)
+mohawk_dma_clean_range:
        bic     r0, r0, #CACHE_DLINESIZE - 1
 1:     mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
        add     r0, r0, #CACHE_DLINESIZE
@@ -268,6 +268,30 @@ ENTRY(mohawk_dma_flush_range)
        mcr     p15, 0, r0, c7, c10, 4          @ drain WB
        mov     pc, lr
 
+/*
+ *     dma_map_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(mohawk_dma_map_area)
+       add     r1, r1, r0
+       cmp     r2, #DMA_TO_DEVICE
+       beq     mohawk_dma_clean_range
+       bcs     mohawk_dma_inv_range
+       b       mohawk_dma_flush_range
+ENDPROC(mohawk_dma_map_area)
+
+/*
+ *     dma_unmap_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(mohawk_dma_unmap_area)
+       mov     pc, lr
+ENDPROC(mohawk_dma_unmap_area)
+
 ENTRY(mohawk_cache_fns)
        .long   mohawk_flush_kern_cache_all
        .long   mohawk_flush_user_cache_all
@@ -275,8 +299,8 @@ ENTRY(mohawk_cache_fns)
        .long   mohawk_coherent_kern_range
        .long   mohawk_coherent_user_range
        .long   mohawk_flush_kern_dcache_area
-       .long   mohawk_dma_inv_range
-       .long   mohawk_dma_clean_range
+       .long   mohawk_dma_map_area
+       .long   mohawk_dma_unmap_area
        .long   mohawk_dma_flush_range
 
 ENTRY(cpu_mohawk_dcache_clean_area)
index 8e4f6dca89976c8809933a96fe76600720d133bf..e5797f1c1db7d0dd4ccf06ff308655be1d2aa2a9 100644 (file)
@@ -257,7 +257,7 @@ ENTRY(xsc3_flush_kern_dcache_area)
  *     - start  - virtual start address
  *     - end    - virtual end address
  */
-ENTRY(xsc3_dma_inv_range)
+xsc3_dma_inv_range:
        tst     r0, #CACHELINESIZE - 1
        bic     r0, r0, #CACHELINESIZE - 1
        mcrne   p15, 0, r0, c7, c10, 1          @ clean L1 D line
@@ -278,7 +278,7 @@ ENTRY(xsc3_dma_inv_range)
  *     - start  - virtual start address
  *     - end    - virtual end address
  */
-ENTRY(xsc3_dma_clean_range)
+xsc3_dma_clean_range:
        bic     r0, r0, #CACHELINESIZE - 1
 1:     mcr     p15, 0, r0, c7, c10, 1          @ clean L1 D line
        add     r0, r0, #CACHELINESIZE
@@ -304,6 +304,30 @@ ENTRY(xsc3_dma_flush_range)
        mcr     p15, 0, r0, c7, c10, 4          @ data write barrier
        mov     pc, lr
 
+/*
+ *     dma_map_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(xsc3_dma_map_area)
+       add     r1, r1, r0
+       cmp     r2, #DMA_TO_DEVICE
+       beq     xsc3_dma_clean_range
+       bcs     xsc3_dma_inv_range
+       b       xsc3_dma_flush_range
+ENDPROC(xsc3_dma_map_area)
+
+/*
+ *     dma_unmap_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(xsc3_dma_unmap_area)
+       mov     pc, lr
+ENDPROC(xsc3_dma_unmap_area)
+
 ENTRY(xsc3_cache_fns)
        .long   xsc3_flush_kern_cache_all
        .long   xsc3_flush_user_cache_all
@@ -311,8 +335,8 @@ ENTRY(xsc3_cache_fns)
        .long   xsc3_coherent_kern_range
        .long   xsc3_coherent_user_range
        .long   xsc3_flush_kern_dcache_area
-       .long   xsc3_dma_inv_range
-       .long   xsc3_dma_clean_range
+       .long   xsc3_dma_map_area
+       .long   xsc3_dma_unmap_area
        .long   xsc3_dma_flush_range
 
 ENTRY(cpu_xsc3_dcache_clean_area)
index 93df47265f2dfda487fcb7c11425d14b0a9ea02f..63037e2162f201ba76ad34604c2cd09ab450d71b 100644 (file)
@@ -315,7 +315,7 @@ ENTRY(xscale_flush_kern_dcache_area)
  *     - start  - virtual start address
  *     - end    - virtual end address
  */
-ENTRY(xscale_dma_inv_range)
+xscale_dma_inv_range:
        tst     r0, #CACHELINESIZE - 1
        bic     r0, r0, #CACHELINESIZE - 1
        mcrne   p15, 0, r0, c7, c10, 1          @ clean D entry
@@ -336,7 +336,7 @@ ENTRY(xscale_dma_inv_range)
  *     - start  - virtual start address
  *     - end    - virtual end address
  */
-ENTRY(xscale_dma_clean_range)
+xscale_dma_clean_range:
        bic     r0, r0, #CACHELINESIZE - 1
 1:     mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
        add     r0, r0, #CACHELINESIZE
@@ -363,6 +363,43 @@ ENTRY(xscale_dma_flush_range)
        mcr     p15, 0, r0, c7, c10, 4          @ Drain Write (& Fill) Buffer
        mov     pc, lr
 
+/*
+ *     dma_map_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(xscale_dma_map_area)
+       add     r1, r1, r0
+       cmp     r2, #DMA_TO_DEVICE
+       beq     xscale_dma_clean_range
+       bcs     xscale_dma_inv_range
+       b       xscale_dma_flush_range
+ENDPROC(xscale_dma_map_area)
+
+/*
+ *     dma_map_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(xscale_dma_a0_map_area)
+       add     r1, r1, r0
+       teq     r2, #DMA_TO_DEVICE
+       beq     xscale_dma_clean_range
+       b       xscale_dma_flush_range
+ENDPROC(xscsale_dma_a0_map_area)
+
+/*
+ *     dma_unmap_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(xscale_dma_unmap_area)
+       mov     pc, lr
+ENDPROC(xscale_dma_unmap_area)
+
 ENTRY(xscale_cache_fns)
        .long   xscale_flush_kern_cache_all
        .long   xscale_flush_user_cache_all
@@ -370,8 +407,8 @@ ENTRY(xscale_cache_fns)
        .long   xscale_coherent_kern_range
        .long   xscale_coherent_user_range
        .long   xscale_flush_kern_dcache_area
-       .long   xscale_dma_inv_range
-       .long   xscale_dma_clean_range
+       .long   xscale_dma_map_area
+       .long   xscale_dma_unmap_area
        .long   xscale_dma_flush_range
 
 /*
@@ -394,8 +431,8 @@ ENTRY(xscale_80200_A0_A1_cache_fns)
        .long   xscale_coherent_kern_range
        .long   xscale_coherent_user_range
        .long   xscale_flush_kern_dcache_area
-       .long   xscale_dma_flush_range
-       .long   xscale_dma_clean_range
+       .long   xscale_dma_a0_map_area
+       .long   xscale_dma_unmap_area
        .long   xscale_dma_flush_range
 
 ENTRY(cpu_xscale_dcache_clean_area)
index ad80752cb9fb2d721479904fd58a7b94950ca142..ef3e2653b90ceb1966bb64e1bb14ad087c966895 100644 (file)
@@ -132,7 +132,7 @@ static irqreturn_t arm11_pmu_interrupt(int irq, void *arg)
        return IRQ_HANDLED;
 }
 
-int arm11_request_interrupts(int *irqs, int nr)
+int arm11_request_interrupts(const int *irqs, int nr)
 {
        unsigned int i;
        int ret = 0;
@@ -153,7 +153,7 @@ int arm11_request_interrupts(int *irqs, int nr)
        return ret;
 }
 
-void arm11_release_interrupts(int *irqs, int nr)
+void arm11_release_interrupts(const int *irqs, int nr)
 {
        unsigned int i;
 
index 6f8538e5a96078a05d0a751e8cbf61ad78e4ceb6..1902b99d9dfdd23b67e98915864c602c0892bf4e 100644 (file)
@@ -39,7 +39,7 @@
 int arm11_setup_pmu(void);
 int arm11_start_pmu(void);
 int arm11_stop_pmu(void);
-int arm11_request_interrupts(int *, int);
-void arm11_release_interrupts(int *, int);
+int arm11_request_interrupts(const int *, int);
+void arm11_release_interrupts(const int *, int);
 
 #endif
index 4ce0f9801e2ef2c5ea9d92e29ec1c680b8335aec..f73ce875a395012c7f7b9500a5af1abbecafc438 100644 (file)
@@ -32,6 +32,7 @@
 /* #define DEBUG */
 #include <linux/types.h>
 #include <linux/errno.h>
+#include <linux/err.h>
 #include <linux/sched.h>
 #include <linux/oprofile.h>
 #include <linux/interrupt.h>
@@ -43,6 +44,7 @@
 #include <mach/hardware.h>
 #include <mach/board-eb.h>
 #include <asm/system.h>
+#include <asm/pmu.h>
 
 #include "op_counter.h"
 #include "op_arm_model.h"
@@ -58,6 +60,7 @@
  * Bitmask of used SCU counters
  */
 static unsigned int scu_em_used;
+static const struct pmu_irqs *pmu_irqs;
 
 /*
  * 2 helper fns take a counter number from 0-7 (not the userspace-visible counter number)
@@ -225,33 +228,40 @@ static int em_setup_ctrs(void)
        return 0;
 }
 
-static int arm11_irqs[] = {
-       [0]     = IRQ_EB11MP_PMU_CPU0,
-       [1]     = IRQ_EB11MP_PMU_CPU1,
-       [2]     = IRQ_EB11MP_PMU_CPU2,
-       [3]     = IRQ_EB11MP_PMU_CPU3
-};
-
 static int em_start(void)
 {
        int ret;
 
-       ret = arm11_request_interrupts(arm11_irqs, ARRAY_SIZE(arm11_irqs));
+       pmu_irqs = reserve_pmu();
+       if (IS_ERR(pmu_irqs)) {
+               ret = PTR_ERR(pmu_irqs);
+               goto out;
+       }
+
+       ret = arm11_request_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs);
        if (ret == 0) {
                em_call_function(arm11_start_pmu);
 
                ret = scu_start();
-               if (ret)
-                       arm11_release_interrupts(arm11_irqs, ARRAY_SIZE(arm11_irqs));
+               if (ret) {
+                       arm11_release_interrupts(pmu_irqs->irqs,
+                                                pmu_irqs->num_irqs);
+               } else {
+                       release_pmu(pmu_irqs);
+                       pmu_irqs = NULL;
+               }
        }
+
+out:
        return ret;
 }
 
 static void em_stop(void)
 {
        em_call_function(arm11_stop_pmu);
-       arm11_release_interrupts(arm11_irqs, ARRAY_SIZE(arm11_irqs));
+       arm11_release_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs);
        scu_stop();
+       release_pmu(pmu_irqs);
 }
 
 /*
@@ -283,15 +293,7 @@ static int em_setup(void)
        em_route_irq(IRQ_EB11MP_PMU_SCU6, 3);
        em_route_irq(IRQ_EB11MP_PMU_SCU7, 3);
 
-       /*
-        * Send CP15 PMU interrupts to the owner CPU.
-        */
-       em_route_irq(IRQ_EB11MP_PMU_CPU0, 0);
-       em_route_irq(IRQ_EB11MP_PMU_CPU1, 1);
-       em_route_irq(IRQ_EB11MP_PMU_CPU2, 2);
-       em_route_irq(IRQ_EB11MP_PMU_CPU3, 3);
-
-       return 0;
+       return init_pmu();
 }
 
 struct op_arm_model_spec op_mpcore_spec = {
index f7d2ec5ee9a1282be6f6089625b97906fbe9df0d..a22357a2fd08270ce4f369443ec966b1f317ee6c 100644 (file)
 /* #define DEBUG */
 #include <linux/types.h>
 #include <linux/errno.h>
+#include <linux/err.h>
 #include <linux/sched.h>
 #include <linux/oprofile.h>
 #include <linux/interrupt.h>
 #include <asm/irq.h>
 #include <asm/system.h>
+#include <asm/pmu.h>
 
 #include "op_counter.h"
 #include "op_arm_model.h"
 #include "op_model_arm11_core.h"
 
-static int irqs[] = {
-#ifdef CONFIG_ARCH_OMAP2
-       3,
-#endif
-#ifdef CONFIG_ARCH_BCMRING
-       IRQ_PMUIRQ, /* for BCMRING, ARM PMU interrupt is 43 */
-#endif
-};
+static const struct pmu_irqs *pmu_irqs;
 
 static void armv6_pmu_stop(void)
 {
        arm11_stop_pmu();
-       arm11_release_interrupts(irqs, ARRAY_SIZE(irqs));
+       arm11_release_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs);
+       release_pmu(pmu_irqs);
+       pmu_irqs = NULL;
 }
 
 static int armv6_pmu_start(void)
 {
        int ret;
 
-       ret = arm11_request_interrupts(irqs, ARRAY_SIZE(irqs));
-       if (ret >= 0)
+       pmu_irqs = reserve_pmu();
+       if (IS_ERR(pmu_irqs)) {
+               ret = PTR_ERR(pmu_irqs);
+               goto out;
+       }
+
+       ret = arm11_request_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs);
+       if (ret >= 0) {
                ret = arm11_start_pmu();
+       } else {
+               release_pmu(pmu_irqs);
+               pmu_irqs = NULL;
+       }
 
+out:
        return ret;
 }
 
index 2088a6c0cc0e36f3e8ba23239f1a62fbb80e4858..8642d0891ae15eac8f2de05e6b02a381ba7cf131 100644 (file)
  */
 #include <linux/types.h>
 #include <linux/errno.h>
+#include <linux/err.h>
 #include <linux/oprofile.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/smp.h>
 
+#include <asm/pmu.h>
+
 #include "op_counter.h"
 #include "op_arm_model.h"
 #include "op_model_v7.h"
@@ -295,7 +298,7 @@ static irqreturn_t armv7_pmnc_interrupt(int irq, void *arg)
        return IRQ_HANDLED;
 }
 
-int armv7_request_interrupts(int *irqs, int nr)
+int armv7_request_interrupts(const int *irqs, int nr)
 {
        unsigned int i;
        int ret = 0;
@@ -318,7 +321,7 @@ int armv7_request_interrupts(int *irqs, int nr)
        return ret;
 }
 
-void armv7_release_interrupts(int *irqs, int nr)
+void armv7_release_interrupts(const int *irqs, int nr)
 {
        unsigned int i;
 
@@ -362,12 +365,7 @@ static void armv7_pmnc_dump_regs(void)
 }
 #endif
 
-
-static int irqs[] = {
-#ifdef CONFIG_ARCH_OMAP3
-       INT_34XX_BENCH_MPU_EMUL,
-#endif
-};
+static const struct pmu_irqs *pmu_irqs;
 
 static void armv7_pmnc_stop(void)
 {
@@ -375,19 +373,29 @@ static void armv7_pmnc_stop(void)
        armv7_pmnc_dump_regs();
 #endif
        armv7_stop_pmnc();
-       armv7_release_interrupts(irqs, ARRAY_SIZE(irqs));
+       armv7_release_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs);
+       release_pmu(pmu_irqs);
+       pmu_irqs = NULL;
 }
 
 static int armv7_pmnc_start(void)
 {
        int ret;
 
+       pmu_irqs = reserve_pmu();
+       if (IS_ERR(pmu_irqs))
+               return PTR_ERR(pmu_irqs);
+
 #ifdef DEBUG
        armv7_pmnc_dump_regs();
 #endif
-       ret = armv7_request_interrupts(irqs, ARRAY_SIZE(irqs));
-       if (ret >= 0)
+       ret = armv7_request_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs);
+       if (ret >= 0) {
                armv7_start_pmnc();
+       } else {
+               release_pmu(pmu_irqs);
+               pmu_irqs = NULL;
+       }
 
        return ret;
 }
index 0e19bcc2e1007eb75beb929ab0adc9a920be195d..9ca334b39c75f8fd76b4b365445ef03c24c0127b 100644 (file)
@@ -97,7 +97,7 @@
 int armv7_setup_pmu(void);
 int armv7_start_pmu(void);
 int armv7_stop_pmu(void);
-int armv7_request_interrupts(int *, int);
-void armv7_release_interrupts(int *, int);
+int armv7_request_interrupts(const int *, int);
+void armv7_release_interrupts(const int *, int);
 
 #endif
index 724ab9ce252674ff02d0e319cc25cd2a7b22da01..1d34a02048bd3a8da91ef1c350dc9656fcbedbd9 100644 (file)
 /* #define DEBUG */
 #include <linux/types.h>
 #include <linux/errno.h>
+#include <linux/err.h>
 #include <linux/sched.h>
 #include <linux/oprofile.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 
 #include <asm/cputype.h>
+#include <asm/pmu.h>
 
 #include "op_counter.h"
 #include "op_arm_model.h"
 #define        PMU_RESET       (CCNT_RESET | PMN_RESET)
 #define PMU_CNT64      0x008   /* Make CCNT count every 64th cycle */
 
-/* TODO do runtime detection */
-#ifdef CONFIG_ARCH_IOP32X
-#define XSCALE_PMU_IRQ  IRQ_IOP32X_CORE_PMU
-#endif
-#ifdef CONFIG_ARCH_IOP33X
-#define XSCALE_PMU_IRQ  IRQ_IOP33X_CORE_PMU
-#endif
-#ifdef CONFIG_ARCH_PXA
-#define XSCALE_PMU_IRQ  IRQ_PMU
-#endif
-
 /*
  * Different types of events that can be counted by the XScale PMU
  * as used by Oprofile userspace. Here primarily for documentation
@@ -367,6 +358,8 @@ static irqreturn_t xscale_pmu_interrupt(int irq, void *arg)
        return IRQ_HANDLED;
 }
 
+static const struct pmu_irqs *pmu_irqs;
+
 static void xscale_pmu_stop(void)
 {
        u32 pmnc = read_pmnc();
@@ -374,20 +367,30 @@ static void xscale_pmu_stop(void)
        pmnc &= ~PMU_ENABLE;
        write_pmnc(pmnc);
 
-       free_irq(XSCALE_PMU_IRQ, results);
+       free_irq(pmu_irqs->irqs[0], results);
+       release_pmu(pmu_irqs);
+       pmu_irqs = NULL;
 }
 
 static int xscale_pmu_start(void)
 {
        int ret;
-       u32 pmnc = read_pmnc();
+       u32 pmnc;
+
+       pmu_irqs = reserve_pmu();
+       if (IS_ERR(pmu_irqs))
+               return PTR_ERR(pmu_irqs);
+
+       pmnc = read_pmnc();
 
-       ret = request_irq(XSCALE_PMU_IRQ, xscale_pmu_interrupt, IRQF_DISABLED,
-                       "XScale PMU", (void *)results);
+       ret = request_irq(pmu_irqs->irqs[0], xscale_pmu_interrupt,
+                         IRQF_DISABLED, "XScale PMU", (void *)results);
 
        if (ret < 0) {
                printk(KERN_ERR "oprofile: unable to request IRQ%d for XScale PMU\n",
-                       XSCALE_PMU_IRQ);
+                      pmu_irqs->irqs[0]);
+               release_pmu(pmu_irqs);
+               pmu_irqs = NULL;
                return ret;
        }
 
index ed0bbece0d6164d7613a4908cd0f9972986990c5..e15bc17db90b0fc845cf44c0f27dd9e4cec5e51a 100644 (file)
@@ -34,7 +34,8 @@ void * __iomem __iop3xx_ioremap(unsigned long cookie, size_t size,
                retval = (void *) IOP3XX_PMMR_PHYS_TO_VIRT(cookie);
                break;
        default:
-               retval = __arm_ioremap(cookie, size, mtype);
+               retval = __arm_ioremap_caller(cookie, size, mtype,
+                               __builtin_return_address(0));
        }
 
        return retval;
index 996cbac6932c77995650735715e9784c8bb5fbb5..6cee38df58b27c145841a571e35e645175189ad3 100644 (file)
@@ -13,3 +13,7 @@ obj-$(CONFIG_USB_EHCI_MXC) += ehci.o
 obj-$(CONFIG_MXC_ULPI) += ulpi.o
 obj-$(CONFIG_ARCH_MXC_AUDMUX_V1) += audmux-v1.o
 obj-$(CONFIG_ARCH_MXC_AUDMUX_V2) += audmux-v2.o
+ifdef CONFIG_SND_IMX_SOC
+obj-y += ssi-fiq.o
+obj-y += ssi-fiq-ksym.o
+endif
index 15b2b148a105c02fa74ba392c33f4eb0de1fc1a8..5a6ae1b9e1e8abe4533e6d61de682042c33820df 100644 (file)
@@ -52,7 +52,7 @@
 #define UART_PADDR     MXC91231_UART2_BASE_ADDR
 #define UART_VADDR     MXC91231_AIPS1_IO_ADDRESS(MXC91231_UART2_BASE_ADDR)
 #endif
-               .macro  addruart,rx
+               .macro  addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                 @ MMU enabled?
                ldreq   \rx, =UART_PADDR        @ physical
index 62d97623412f1061cee30d249823c5e98416f37f..44243a278434b027d604ed590e43d9cdb5749653 100644 (file)
@@ -21,6 +21,6 @@
 #define __ASM_ARCH_MXC_VMALLOC_H__
 
 /* vmalloc ending address */
-#define VMALLOC_END       0xF4000000
+#define VMALLOC_END       0xf4000000UL
 
 #endif /* __ASM_ARCH_MXC_VMALLOC_H__ */
diff --git a/arch/arm/plat-mxc/ssi-fiq-ksym.c b/arch/arm/plat-mxc/ssi-fiq-ksym.c
new file mode 100644 (file)
index 0000000..b5fad45
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Exported ksyms for the SSI FIQ handler
+ *
+ * Copyright (C) 2009, Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+
+#include <mach/ssi.h>
+
+EXPORT_SYMBOL(imx_ssi_fiq_tx_buffer);
+EXPORT_SYMBOL(imx_ssi_fiq_rx_buffer);
+EXPORT_SYMBOL(imx_ssi_fiq_start);
+EXPORT_SYMBOL(imx_ssi_fiq_end);
+EXPORT_SYMBOL(imx_ssi_fiq_base);
+
diff --git a/arch/arm/plat-mxc/ssi-fiq.S b/arch/arm/plat-mxc/ssi-fiq.S
new file mode 100644 (file)
index 0000000..4ddce56
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ *  Copyright (C) 2009 Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+/*
+ * r8  = bit 0-15: tx offset, bit 16-31: tx buffer size
+ * r9  = bit 0-15: rx offset, bit 16-31: rx buffer size
+ */
+
+#define SSI_STX0       0x00
+#define SSI_SRX0       0x08
+#define SSI_SISR       0x14
+#define SSI_SIER       0x18
+#define SSI_SACNT      0x38
+
+#define SSI_SACNT_AC97EN       (1 << 0)
+
+#define SSI_SIER_TFE0_EN       (1 << 0)
+#define SSI_SISR_TFE0          (1 << 0)
+#define SSI_SISR_RFF0          (1 << 2)
+#define SSI_SIER_RFF0_EN       (1 << 2)
+
+               .text
+               .global imx_ssi_fiq_start
+               .global imx_ssi_fiq_end
+               .global imx_ssi_fiq_base
+               .global imx_ssi_fiq_rx_buffer
+               .global imx_ssi_fiq_tx_buffer
+
+imx_ssi_fiq_start:
+               ldr r12, imx_ssi_fiq_base
+
+               /* TX */
+               ldr r11, imx_ssi_fiq_tx_buffer
+
+               /* shall we send? */
+               ldr r13, [r12, #SSI_SIER]
+               tst r13, #SSI_SIER_TFE0_EN
+               beq 1f
+
+               /* TX FIFO empty? */
+               ldr r13, [r12, #SSI_SISR]
+               tst r13, #SSI_SISR_TFE0
+               beq 1f
+
+               mov r10, #0x10000
+               sub r10, #1
+               and r10, r10, r8        /* r10: current buffer offset */
+
+               add r11, r11, r10
+
+               ldrh r13, [r11]
+               strh r13, [r12, #SSI_STX0]
+
+               ldrh r13, [r11, #2]
+               strh r13, [r12, #SSI_STX0]
+
+               ldrh r13, [r11, #4]
+               strh r13, [r12, #SSI_STX0]
+
+               ldrh r13, [r11, #6]
+               strh r13, [r12, #SSI_STX0]
+
+               add r10, #8
+               lsr r13, r8, #16        /* r13: buffer size */
+               cmp r10, r13
+               lslgt r8, r13, #16
+               addle r8, #8
+1:
+               /* RX */
+
+               /* shall we receive? */
+               ldr r13, [r12, #SSI_SIER]
+               tst r13, #SSI_SIER_RFF0_EN
+               beq 1f
+
+               /* RX FIFO full? */
+               ldr r13, [r12, #SSI_SISR]
+               tst r13, #SSI_SISR_RFF0
+               beq 1f
+
+               ldr r11, imx_ssi_fiq_rx_buffer
+
+               mov r10, #0x10000
+               sub r10, #1
+               and r10, r10, r9        /* r10: current buffer offset */
+
+               add r11, r11, r10
+
+               ldr r13, [r12, #SSI_SACNT]
+               tst r13, #SSI_SACNT_AC97EN
+
+               ldr r13, [r12, #SSI_SRX0]
+               strh r13, [r11]
+
+               ldr r13, [r12, #SSI_SRX0]
+               strh r13, [r11, #2]
+
+               /* dummy read to skip slot 12 */
+               ldrne r13, [r12, #SSI_SRX0]
+
+               ldr r13, [r12, #SSI_SRX0]
+               strh r13, [r11, #4]
+
+               ldr r13, [r12, #SSI_SRX0]
+               strh r13, [r11, #6]
+
+               /* dummy read to skip slot 12 */
+               ldrne r13, [r12, #SSI_SRX0]
+
+               add r10, #8
+               lsr r13, r9, #16        /* r13: buffer size */
+               cmp r10, r13
+               lslgt r9, r13, #16
+               addle r9, #8
+
+1:
+               @ return from FIQ
+               subs    pc, lr, #4
+imx_ssi_fiq_base:
+               .word 0x0
+imx_ssi_fiq_rx_buffer:
+               .word 0x0
+imx_ssi_fiq_tx_buffer:
+               .word 0x0
+imx_ssi_fiq_end:
+
diff --git a/arch/arm/plat-nomadik/include/plat/i2c.h b/arch/arm/plat-nomadik/include/plat/i2c.h
new file mode 100644 (file)
index 0000000..1621db6
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2009 ST-Ericsson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ */
+#ifndef __PLAT_I2C_H
+#define __PLAT_I2C_H
+
+enum i2c_freq_mode {
+       I2C_FREQ_MODE_STANDARD,         /* up to 100 Kb/s */
+       I2C_FREQ_MODE_FAST,             /* up to 400 Kb/s */
+       I2C_FREQ_MODE_FAST_PLUS,        /* up to 1 Mb/s */
+       I2C_FREQ_MODE_HIGH_SPEED        /* up to 3.4 Mb/s */
+};
+
+/**
+ * struct nmk_i2c_controller - client specific controller configuration
+ * @clk_freq:  clock frequency for the operation mode
+ * @slsu:      Slave data setup time in ns.
+ *             The needed setup time for three modes of operation
+ *             are 250ns, 100ns and 10ns respectively thus leading
+ *             to the values of 14, 6, 2 for a 48 MHz i2c clk
+ * @tft:       Tx FIFO Threshold in bytes
+ * @rft:       Rx FIFO Threshold in bytes
+ * @sm:                speed mode
+ */
+struct nmk_i2c_controller {
+       unsigned long   clk_freq;
+       unsigned short  slsu;
+       unsigned char   tft;
+       unsigned char   rft;
+       enum i2c_freq_mode      sm;
+};
+
+#endif /* __PLAT_I2C_H */
index e2ea04a4c8a1b06b2c8d477b631fe38251fe9018..2e3eec6608647cafa6d1a435cc3681931b35f970 100644 (file)
@@ -22,6 +22,7 @@ config ARCH_OMAP3
        bool "TI OMAP3"
        select CPU_V7
        select COMMON_CLKDEV
+       select ARM_L1_CACHE_SHIFT_6
 
 config ARCH_OMAP4
        bool "TI OMAP4"
index ef870de43c29b9c12d7491e0262bf1815b7e7865..c7d628ecb467aa57a85090af29a9904488643604 100644 (file)
@@ -40,6 +40,7 @@
 #define OMAP44XX_GIC_CPU_BASE          0x48240100
 #define OMAP44XX_SCU_BASE              0x48240000
 #define OMAP44XX_LOCAL_TWD_BASE                0x48240600
+#define OMAP44XX_L2CACHE_BASE          0x48242000
 #define OMAP44XX_WKUPGEN_BASE          0x48281000
 
 #define OMAP44XX_MAILBOX_BASE          (L4_44XX_BASE + 0xF4000)
index 0cfd54f519c4012eb0eb6fe518bf19ce0d3ebf42..4cbd4fb3232c86bcc50e27f05246e9577f9daa17 100644 (file)
@@ -128,7 +128,7 @@ void __iomem *omap_ioremap(unsigned long p, size_t size, unsigned int type)
                        return XLATE(p, L4_EMU_44XX_PHYS, L4_EMU_44XX_VIRT);
        }
 #endif
-       return __arm_ioremap(p, size, type);
+       return __arm_ioremap_caller(p, size, type, __builtin_return_address(0));
 }
 EXPORT_SYMBOL(omap_ioremap);
 
index bfd2ca6e3074a6d4abd4d5706dcc4bf9d0031099..299d95f365c961dc21aad21cacd88730c183ce84 100644 (file)
@@ -15,6 +15,6 @@
 #ifndef __ASM_ARCH_VMALLOC_H
 #define __ASM_ARCH_VMALLOC_H
 
-#define VMALLOC_END      (0xE0000000)
+#define VMALLOC_END      (0xe0000000UL)
 
 #endif /* __ASM_ARCH_VMALLOC_H */
index 5d2f19a09e44c7bc02b05bfbe16c420769b29104..e593a2a801c63370efea993d529adf8b8960e0f4 100644 (file)
@@ -1126,9 +1126,8 @@ static int __init clk_init(void)
                        if (ops && ops->set_parent)
                                ops->set_parent(cl->clk, cl->clk->parent);
                }
-
-               clkdev_add(cl);
        }
+       clkdev_add_table(onchip_clks, ARRAY_SIZE(onchip_clks));
        return 0;
 }
 
index fb3b969bf0a24fc4de8a9ba87e1936a5fe9c75a5..1b9348bf0e4926b542bea6d1bfcc4a9cd2e29440 100644 (file)
@@ -16,7 +16,7 @@
  * http://www.gnu.org/copyleft/gpl.html
  */
 
-               .macro  addruart,rx
+               .macro  addruart, rx, tmp
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                 @ MMU enabled?
                moveq   \rx, #0x80000000        @ physical base address
index 541b880c1863627ac36c1e84f36de0221df4d632..943c1a29d641470fa733b7cf7fd3604f15433e8d 100644 (file)
@@ -9,4 +9,4 @@
  * http://www.opensource.org/licenses/gpl-license.html
  * http://www.gnu.org/copyleft/gpl.html
  */
-#define VMALLOC_END       (0xF0000000)
+#define VMALLOC_END       0xf0000000UL
index a63c4be99b36eb576cbf2314aab9725960f2ea1d..7f3f59fcaa2199dda10eebd5b7bfa62348643342 100644 (file)
@@ -433,7 +433,11 @@ static inline void vfp_pm_init(void) { }
  * saved one. This function is used by the ptrace mechanism.
  */
 #ifdef CONFIG_SMP
-void vfp_sync_state(struct thread_info *thread)
+void vfp_sync_hwstate(struct thread_info *thread)
+{
+}
+
+void vfp_flush_hwstate(struct thread_info *thread)
 {
        /*
         * On SMP systems, the VFP state is automatically saved at every
@@ -444,35 +448,48 @@ void vfp_sync_state(struct thread_info *thread)
        thread->vfpstate.hard.cpu = NR_CPUS;
 }
 #else
-void vfp_sync_state(struct thread_info *thread)
+void vfp_sync_hwstate(struct thread_info *thread)
 {
        unsigned int cpu = get_cpu();
-       u32 fpexc = fmrx(FPEXC);
 
        /*
-        * If VFP is enabled, the previous state was already saved and
-        * last_VFP_context updated.
+        * If the thread we're interested in is the current owner of the
+        * hardware VFP state, then we need to save its state.
         */
-       if (fpexc & FPEXC_EN)
-               goto out;
+       if (last_VFP_context[cpu] == &thread->vfpstate) {
+               u32 fpexc = fmrx(FPEXC);
 
-       if (!last_VFP_context[cpu])
-               goto out;
+               /*
+                * Save the last VFP state on this CPU.
+                */
+               fmxr(FPEXC, fpexc | FPEXC_EN);
+               vfp_save_state(&thread->vfpstate, fpexc | FPEXC_EN);
+               fmxr(FPEXC, fpexc);
+       }
 
-       /*
-        * Save the last VFP state on this CPU.
-        */
-       fmxr(FPEXC, fpexc | FPEXC_EN);
-       vfp_save_state(last_VFP_context[cpu], fpexc);
-       fmxr(FPEXC, fpexc);
+       put_cpu();
+}
+
+void vfp_flush_hwstate(struct thread_info *thread)
+{
+       unsigned int cpu = get_cpu();
 
        /*
-        * Set the context to NULL to force a reload the next time the thread
-        * uses the VFP.
+        * If the thread we're interested in is the current owner of the
+        * hardware VFP state, then we need to save its state.
         */
-       last_VFP_context[cpu] = NULL;
+       if (last_VFP_context[cpu] == &thread->vfpstate) {
+               u32 fpexc = fmrx(FPEXC);
+
+               fmxr(FPEXC, fpexc & ~FPEXC_EN);
+
+               /*
+                * Set the context to NULL to force a reload the next time
+                * the thread uses the VFP.
+                */
+               last_VFP_context[cpu] = NULL;
+       }
 
-out:
        put_cpu();
 }
 #endif
index fecdda16f4443a7ed957690eeb5ec57cd5d4f5ae..a9ae30c41e746d53e25281d3c8132c5aeba9f09d 100644 (file)
@@ -325,7 +325,7 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 
 struct vm_area_struct;
 extern void update_mmu_cache(struct vm_area_struct * vma,
-                            unsigned long address, pte_t pte);
+                            unsigned long address, pte_t *ptep);
 
 /*
  * Encode and decode a swap entry
index 06677be98ffba5fcb0143dac626bf96235fd1e16..0da23109f817ad5cdb14f87e0b5b84bca3da2ff5 100644 (file)
@@ -101,7 +101,7 @@ static void update_dtlb(unsigned long address, pte_t pte)
 }
 
 void update_mmu_cache(struct vm_area_struct *vma,
-                     unsigned long address, pte_t pte)
+                     unsigned long address, pte_t *ptep)
 {
        unsigned long flags;
 
@@ -110,7 +110,7 @@ void update_mmu_cache(struct vm_area_struct *vma,
                return;
 
        local_irq_save(flags);
-       update_dtlb(address, pte);
+       update_dtlb(address, *ptep);
        local_irq_restore(flags);
 }
 
index 5d75f77f9c733267d323b309eba85e1df34d8617..1a61efc139826870b156eabc26987f9a3319852a 100644 (file)
@@ -133,7 +133,7 @@ static void end_crisv10_irq(unsigned int irq)
 }
 
 static struct irq_chip crisv10_irq_type = {
-       .typename =    "CRISv10",
+       .name =        "CRISv10",
        .startup =     startup_crisv10_irq,
        .shutdown =    shutdown_crisv10_irq,
        .enable =      enable_crisv10_irq,
index 57668db25031ca34bc965ee5abe1612e9f191e76..b6241198fb98d86c72ab48999e40989fdf552411 100644 (file)
@@ -336,7 +336,7 @@ int set_affinity_crisv32_irq(unsigned int irq, const struct cpumask *dest)
 }
 
 static struct irq_chip crisv32_irq_type = {
-       .typename =    "CRISv32",
+       .name =        "CRISv32",
        .startup =     startup_crisv32_irq,
        .shutdown =    shutdown_crisv32_irq,
        .enable =      enable_crisv32_irq,
index 6eb54ea1c97622a6b652d831691b5f1bf58f2ee1..f6f3637a41942f5e3de93925c4026acd11d5dc3a 100644 (file)
@@ -54,7 +54,7 @@ crisv32_pinmux_alloc(int port, int first_pin, int last_pin, enum pin_mode mode)
 
        crisv32_pinmux_init();
 
-       if (port > PORTS)
+       if (port > PORTS || port < 0)
                return -EINVAL;
 
        spin_lock_irqsave(&pinmux_lock, flags);
@@ -197,7 +197,7 @@ crisv32_pinmux_dealloc(int port, int first_pin, int last_pin)
 
        crisv32_pinmux_init();
 
-       if (port > PORTS)
+       if (port > PORTS || port < 0)
                return -EINVAL;
 
        spin_lock_irqsave(&pinmux_lock, flags);
index 0a28c9bedfb722321def3f079ea3d8700dd585e3..18648ef2d8741db3ed8144b3e3a628e49b4f8d0b 100644 (file)
@@ -242,7 +242,7 @@ crisv32_pinmux_dealloc(int port, int first_pin, int last_pin)
 
        crisv32_pinmux_init();
 
-       if (port > PORTS)
+       if (port > PORTS || port < 0)
                return -EINVAL;
 
        spin_lock_irqsave(&pinmux_lock, flags);
index d722ad9ae6261fb952356cfd7473603d3b91415b..38f29eec14a617af2691c8ce35545f1fcc8a4422 100644 (file)
@@ -54,7 +54,7 @@ crisv32_pinmux_alloc(int port, int first_pin, int last_pin, enum pin_mode mode)
 
        crisv32_pinmux_init();
 
-       if (port > PORTS)
+       if (port > PORTS || port < 0)
                return -EINVAL;
 
        spin_lock_irqsave(&pinmux_lock, flags);
@@ -195,7 +195,7 @@ int crisv32_pinmux_dealloc(int port, int first_pin, int last_pin)
 
        crisv32_pinmux_init();
 
-       if (port > PORTS)
+       if (port > PORTS || port < 0)
                return -EINVAL;
 
        spin_lock_irqsave(&pinmux_lock, flags);
index 1fcce00f01f4f1fc1bab0f0c994bff80251333c5..99ea6cd1b1436f03a171ad9e3c42a0205780734d 100644 (file)
@@ -270,7 +270,7 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; /* defined in head.S */
  * Actually I am not sure on what this could be used for.
  */
 static inline void update_mmu_cache(struct vm_area_struct * vma,
-       unsigned long address, pte_t pte)
+       unsigned long address, pte_t *ptep)
 {
 }
 
index b5ce0724a88f6f307292f46601a564f022ddaf2c..6d7b9eda40367c87c4f9e76540e04eab3442f8c8 100644 (file)
@@ -63,7 +63,7 @@ int show_interrupts(struct seq_file *p, void *v)
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
 #endif
-               seq_printf(p, " %14s", irq_desc[i].chip->typename);
+               seq_printf(p, " %14s", irq_desc[i].chip->name);
                seq_printf(p, "  %s", action->name);
 
                for (action=action->next; action; action = action->next)
index 22c60692b5513c7c6f66d49947a16e574ba31835..c18b0d32e63655ed7dc7d26b5ce0c44c5f990c36 100644 (file)
@@ -505,7 +505,7 @@ static inline int pte_file(pte_t pte)
 /*
  * preload information about a newly instantiated PTE into the SCR0/SCR1 PGE cache
  */
-static inline void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
+static inline void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep)
 {
        struct mm_struct *mm;
        unsigned long ampr;
index 2d7f56a98e0f484ce80d544223b4b9923526cb2a..9a50d7dd2a0b65f9b510358ef2016a968aab438a 100644 (file)
@@ -499,23 +499,6 @@ config ARCH_PROC_KCORE_TEXT
        def_bool y
        depends on PROC_KCORE
 
-config IA32_SUPPORT
-       bool "Support for Linux/x86 binaries"
-       help
-         IA-64 processors can execute IA-32 (X86) instructions.  By
-         saying Y here, the kernel will include IA-32 system call
-         emulation support which makes it possible to transparently
-         run IA-32 Linux binaries on an IA-64 Linux system.
-         If in doubt, say Y.
-
-config COMPAT
-       bool
-       depends on IA32_SUPPORT
-       default y
-
-config COMPAT_FOR_U64_ALIGNMENT
-       def_bool COMPAT
-
 config IA64_MCA_RECOVERY
        tristate "MCA recovery from errors other than TLB."
 
index 475e2725fbde6feb6c9d64c024a52a2fd211af35..8ae0d2604ce1201bfe4156b70cc5a47344e8eff7 100644 (file)
@@ -46,7 +46,6 @@ head-y := arch/ia64/kernel/head.o arch/ia64/kernel/init_task.o
 
 libs-y                         += arch/ia64/lib/
 core-y                         += arch/ia64/kernel/ arch/ia64/mm/
-core-$(CONFIG_IA32_SUPPORT)    += arch/ia64/ia32/
 core-$(CONFIG_IA64_DIG)        += arch/ia64/dig/
 core-$(CONFIG_IA64_DIG_VTD)    += arch/ia64/dig/
 core-$(CONFIG_IA64_GENERIC)    += arch/ia64/dig/
index ace41096b47b57ec5e47fb68178ac7b3e7c59724..312b12094a1de4a734f9edc5ee10cb98e3afde6c 100644 (file)
@@ -131,8 +131,6 @@ CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
 CONFIG_ARCH_FLATMEM_ENABLE=y
 CONFIG_ARCH_SPARSEMEM_ENABLE=y
 # CONFIG_VIRTUAL_MEM_MAP is not set
-CONFIG_IA32_SUPPORT=y
-CONFIG_COMPAT=y
 # CONFIG_IA64_MCA_RECOVERY is not set
 CONFIG_PERFMON=y
 CONFIG_IA64_PALINFO=y
index 75645495c2ddc491605ca29e9405b71edf8081f4..6a4cc506fb5fc630c03159c949e1ff1ac9b981f1 100644 (file)
@@ -205,8 +205,6 @@ CONFIG_VIRTUAL_MEM_MAP=y
 CONFIG_HOLES_IN_ZONE=y
 CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y
 CONFIG_HAVE_ARCH_NODEDATA_EXTENSION=y
-CONFIG_IA32_SUPPORT=y
-CONFIG_COMPAT=y
 CONFIG_COMPAT_FOR_U64_ALIGNMENT=y
 CONFIG_IA64_MCA_RECOVERY=y
 CONFIG_PERFMON=y
index e86fbd39c79509df11bb9720355b7146c28ca903..2dc185b0f9a32f5360f5de05a50ad09f944fb125 100644 (file)
@@ -139,8 +139,6 @@ CONFIG_ARCH_SPARSEMEM_ENABLE=y
 CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
 CONFIG_NUMA=y
 CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y
-CONFIG_IA32_SUPPORT=y
-CONFIG_COMPAT=y
 CONFIG_IA64_MCA_RECOVERY=y
 CONFIG_PERFMON=y
 CONFIG_IA64_PALINFO=y
index 546a772f438e9e9e335d7a9d886019ce7f0be126..21a23cdfd41ce2435ba767dd4e2989373357f8eb 100644 (file)
@@ -130,8 +130,6 @@ CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
 CONFIG_ARCH_FLATMEM_ENABLE=y
 CONFIG_ARCH_SPARSEMEM_ENABLE=y
 # CONFIG_VIRTUAL_MEM_MAP is not set
-CONFIG_IA32_SUPPORT=y
-CONFIG_COMPAT=y
 # CONFIG_IA64_MCA_RECOVERY is not set
 # CONFIG_PERFMON is not set
 CONFIG_IA64_PALINFO=m
index c522edf23c623732c06709cd05df178ac794d17e..c5a5ea9d54ae32910536d635ae8936501cd9f643 100644 (file)
@@ -154,7 +154,6 @@ CONFIG_ARCH_SPARSEMEM_ENABLE=y
 CONFIG_ARCH_POPULATES_NODE_MAP=y
 CONFIG_VIRTUAL_MEM_MAP=y
 CONFIG_HOLES_IN_ZONE=y
-# CONFIG_IA32_SUPPORT is not set
 CONFIG_IA64_MCA_RECOVERY=y
 CONFIG_PERFMON=y
 CONFIG_IA64_PALINFO=y
index 0bb0714dc19d1303c48d7df32521d0d7891e1b5d..c67eafc4bb3848da706f5b82e806376793b08800 100644 (file)
@@ -200,8 +200,6 @@ CONFIG_ARCH_SPARSEMEM_ENABLE=y
 CONFIG_ARCH_POPULATES_NODE_MAP=y
 CONFIG_VIRTUAL_MEM_MAP=y
 CONFIG_HOLES_IN_ZONE=y
-# CONFIG_IA32_SUPPORT is not set
-# CONFIG_COMPAT_FOR_U64_ALIGNMENT is not set
 CONFIG_IA64_MCA_RECOVERY=y
 CONFIG_PERFMON=y
 CONFIG_IA64_PALINFO=y
index 514f0635dafe485f6097996fa252c84d4c7b3445..3cec65b534c2227bfeb1ad187a0d769e34e18d08 100644 (file)
@@ -150,8 +150,6 @@ CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
 CONFIG_ARCH_POPULATES_NODE_MAP=y
 CONFIG_VIRTUAL_MEM_MAP=y
 CONFIG_HOLES_IN_ZONE=y
-CONFIG_IA32_SUPPORT=y
-CONFIG_COMPAT=y
 CONFIG_IA64_MCA_RECOVERY=y
 CONFIG_PERFMON=y
 CONFIG_IA64_PALINFO=y
index 4abd2c79bb1d738a743deaba611deea743bc6552..22078486d35da9bcb96fe66a35524f4fe31193c1 100644 (file)
@@ -77,7 +77,7 @@ static void aml_nfw_execute(struct ia64_nfw_context *c)
                     c->arg[4], c->arg[5], c->arg[6], c->arg[7]);
 }
 
-static void aml_nfw_read_arg(u8 *offset, u32 bit_width, acpi_integer *value)
+static void aml_nfw_read_arg(u8 *offset, u32 bit_width, u64 *value)
 {
        switch (bit_width) {
        case 8:
@@ -95,7 +95,7 @@ static void aml_nfw_read_arg(u8 *offset, u32 bit_width, acpi_integer *value)
        }
 }
 
-static void aml_nfw_write_arg(u8 *offset, u32 bit_width, acpi_integer *value)
+static void aml_nfw_write_arg(u8 *offset, u32 bit_width, u64 *value)
 {
        switch (bit_width) {
        case 8:
@@ -114,7 +114,7 @@ static void aml_nfw_write_arg(u8 *offset, u32 bit_width, acpi_integer *value)
 }
 
 static acpi_status aml_nfw_handler(u32 function, acpi_physical_address address,
-       u32 bit_width, acpi_integer *value, void *handler_context,
+       u32 bit_width, u64 *value, void *handler_context,
        void *region_context)
 {
        struct ia64_nfw_context *context = handler_context;
diff --git a/arch/ia64/ia32/Makefile b/arch/ia64/ia32/Makefile
deleted file mode 100644 (file)
index baad8c7..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#
-# Makefile for the ia32 kernel emulation subsystem.
-#
-
-obj-y := ia32_entry.o sys_ia32.o ia32_signal.o \
-        ia32_support.o ia32_traps.o binfmt_elf32.o ia32_ldt.o
-obj-$(CONFIG_AUDIT) += audit.o
-
-# Don't let GCC uses f16-f31 so that save_ia32_fpstate_live() and
-# restore_ia32_fpstate_live() can be sure the live register contain user-level state.
-CFLAGS_ia32_signal.o += -mfixed-range=f16-f31
diff --git a/arch/ia64/ia32/audit.c b/arch/ia64/ia32/audit.c
deleted file mode 100644 (file)
index 5c93ddd..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-#include "../../x86/include/asm/unistd_32.h"
-
-unsigned ia32_dir_class[] = {
-#include <asm-generic/audit_dir_write.h>
-~0U
-};
-
-unsigned ia32_chattr_class[] = {
-#include <asm-generic/audit_change_attr.h>
-~0U
-};
-
-unsigned ia32_write_class[] = {
-#include <asm-generic/audit_write.h>
-~0U
-};
-
-unsigned ia32_read_class[] = {
-#include <asm-generic/audit_read.h>
-~0U
-};
-
-unsigned ia32_signal_class[] = {
-#include <asm-generic/audit_signal.h>
-~0U
-};
-
-int ia32_classify_syscall(unsigned syscall)
-{
-       switch(syscall) {
-       case __NR_open:
-               return 2;
-       case __NR_openat:
-               return 3;
-       case __NR_socketcall:
-               return 4;
-       case __NR_execve:
-               return 5;
-       default:
-               return 1;
-       }
-}
diff --git a/arch/ia64/ia32/binfmt_elf32.c b/arch/ia64/ia32/binfmt_elf32.c
deleted file mode 100644 (file)
index c69552b..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * IA-32 ELF support.
- *
- * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com>
- * Copyright (C) 2001 Hewlett-Packard Co
- *     David Mosberger-Tang <davidm@hpl.hp.com>
- *
- * 06/16/00    A. Mallick      initialize csd/ssd/tssd/cflg for ia32_load_state
- * 04/13/01    D. Mosberger    dropped saving tssd in ar.k1---it's not needed
- * 09/14/01    D. Mosberger    fixed memory management for gdt/tss page
- */
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/security.h>
-
-#include <asm/param.h>
-#include <asm/signal.h>
-
-#include "ia32priv.h"
-#include "elfcore32.h"
-
-/* Override some function names */
-#undef start_thread
-#define start_thread                   ia32_start_thread
-#define elf_format                     elf32_format
-#define init_elf_binfmt                        init_elf32_binfmt
-#define exit_elf_binfmt                        exit_elf32_binfmt
-
-#undef CLOCKS_PER_SEC
-#define CLOCKS_PER_SEC IA32_CLOCKS_PER_SEC
-
-extern void ia64_elf32_init (struct pt_regs *regs);
-
-static void elf32_set_personality (void);
-
-static unsigned long __attribute ((unused))
-randomize_stack_top(unsigned long stack_top);
-
-#define setup_arg_pages(bprm,tos,exec)         ia32_setup_arg_pages(bprm,exec)
-#define elf_map                                elf32_map
-
-#undef SET_PERSONALITY
-#define SET_PERSONALITY(ex)    elf32_set_personality()
-
-#define elf_read_implies_exec(ex, have_pt_gnu_stack)   (!(have_pt_gnu_stack))
-
-/* Ugly but avoids duplication */
-#include "../../../fs/binfmt_elf.c"
-
-extern struct page *ia32_shared_page[];
-extern unsigned long *ia32_gdt;
-extern struct page *ia32_gate_page;
-
-int
-ia32_install_shared_page (struct vm_area_struct *vma, struct vm_fault *vmf)
-{
-       vmf->page = ia32_shared_page[smp_processor_id()];
-       get_page(vmf->page);
-       return 0;
-}
-
-int
-ia32_install_gate_page (struct vm_area_struct *vma, struct vm_fault *vmf)
-{
-       vmf->page = ia32_gate_page;
-       get_page(vmf->page);
-       return 0;
-}
-
-
-static const struct vm_operations_struct ia32_shared_page_vm_ops = {
-       .fault = ia32_install_shared_page
-};
-
-static const struct vm_operations_struct ia32_gate_page_vm_ops = {
-       .fault = ia32_install_gate_page
-};
-
-void
-ia64_elf32_init (struct pt_regs *regs)
-{
-       struct vm_area_struct *vma;
-
-       /*
-        * Map GDT below 4GB, where the processor can find it.  We need to map
-        * it with privilege level 3 because the IVE uses non-privileged accesses to these
-        * tables.  IA-32 segmentation is used to protect against IA-32 accesses to them.
-        */
-       vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
-       if (vma) {
-               vma->vm_mm = current->mm;
-               vma->vm_start = IA32_GDT_OFFSET;
-               vma->vm_end = vma->vm_start + PAGE_SIZE;
-               vma->vm_page_prot = PAGE_SHARED;
-               vma->vm_flags = VM_READ|VM_MAYREAD|VM_RESERVED;
-               vma->vm_ops = &ia32_shared_page_vm_ops;
-               down_write(&current->mm->mmap_sem);
-               {
-                       if (insert_vm_struct(current->mm, vma)) {
-                               kmem_cache_free(vm_area_cachep, vma);
-                               up_write(&current->mm->mmap_sem);
-                               BUG();
-                       }
-               }
-               up_write(&current->mm->mmap_sem);
-       }
-
-       /*
-        * When user stack is not executable, push sigreturn code to stack makes
-        * segmentation fault raised when returning to kernel. So now sigreturn
-        * code is locked in specific gate page, which is pointed by pretcode
-        * when setup_frame_ia32
-        */
-       vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
-       if (vma) {
-               vma->vm_mm = current->mm;
-               vma->vm_start = IA32_GATE_OFFSET;
-               vma->vm_end = vma->vm_start + PAGE_SIZE;
-               vma->vm_page_prot = PAGE_COPY_EXEC;
-               vma->vm_flags = VM_READ | VM_MAYREAD | VM_EXEC
-                               | VM_MAYEXEC | VM_RESERVED;
-               vma->vm_ops = &ia32_gate_page_vm_ops;
-               down_write(&current->mm->mmap_sem);
-               {
-                       if (insert_vm_struct(current->mm, vma)) {
-                               kmem_cache_free(vm_area_cachep, vma);
-                               up_write(&current->mm->mmap_sem);
-                               BUG();
-                       }
-               }
-               up_write(&current->mm->mmap_sem);
-       }
-
-       /*
-        * Install LDT as anonymous memory.  This gives us all-zero segment descriptors
-        * until a task modifies them via modify_ldt().
-        */
-       vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
-       if (vma) {
-               vma->vm_mm = current->mm;
-               vma->vm_start = IA32_LDT_OFFSET;
-               vma->vm_end = vma->vm_start + PAGE_ALIGN(IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE);
-               vma->vm_page_prot = PAGE_SHARED;
-               vma->vm_flags = VM_READ|VM_WRITE|VM_MAYREAD|VM_MAYWRITE;
-               down_write(&current->mm->mmap_sem);
-               {
-                       if (insert_vm_struct(current->mm, vma)) {
-                               kmem_cache_free(vm_area_cachep, vma);
-                               up_write(&current->mm->mmap_sem);
-                               BUG();
-                       }
-               }
-               up_write(&current->mm->mmap_sem);
-       }
-
-       ia64_psr(regs)->ac = 0;         /* turn off alignment checking */
-       regs->loadrs = 0;
-       /*
-        *  According to the ABI %edx points to an `atexit' handler.  Since we don't have
-        *  one we'll set it to 0 and initialize all the other registers just to make
-        *  things more deterministic, ala the i386 implementation.
-        */
-       regs->r8 = 0;   /* %eax */
-       regs->r11 = 0;  /* %ebx */
-       regs->r9 = 0;   /* %ecx */
-       regs->r10 = 0;  /* %edx */
-       regs->r13 = 0;  /* %ebp */
-       regs->r14 = 0;  /* %esi */
-       regs->r15 = 0;  /* %edi */
-
-       current->thread.eflag = IA32_EFLAG;
-       current->thread.fsr = IA32_FSR_DEFAULT;
-       current->thread.fcr = IA32_FCR_DEFAULT;
-       current->thread.fir = 0;
-       current->thread.fdr = 0;
-
-       /*
-        * Setup GDTD.  Note: GDTD is the descrambled version of the pseudo-descriptor
-        * format defined by Figure 3-11 "Pseudo-Descriptor Format" in the IA-32
-        * architecture manual. Also note that the only fields that are not ignored are
-        * `base', `limit', 'G', `P' (must be 1) and `S' (must be 0).
-        */
-       regs->r31 = IA32_SEG_UNSCRAMBLE(IA32_SEG_DESCRIPTOR(IA32_GDT_OFFSET, IA32_PAGE_SIZE - 1,
-                                                           0, 0, 0, 1, 0, 0, 0));
-       /* Setup the segment selectors */
-       regs->r16 = (__USER_DS << 16) | __USER_DS; /* ES == DS, GS, FS are zero */
-       regs->r17 = (__USER_DS << 16) | __USER_CS; /* SS, CS; ia32_load_state() sets TSS and LDT */
-
-       ia32_load_segment_descriptors(current);
-       ia32_load_state(current);
-}
-
-/*
- * Undo the override of setup_arg_pages() without this ia32_setup_arg_pages()
- * will suffer infinite self recursion.
- */
-#undef setup_arg_pages
-
-int
-ia32_setup_arg_pages (struct linux_binprm *bprm, int executable_stack)
-{
-       int ret;
-
-       ret = setup_arg_pages(bprm, IA32_STACK_TOP, executable_stack);
-       if (!ret) {
-               /*
-                * Can't do it in ia64_elf32_init(). Needs to be done before
-                * calls to elf32_map()
-                */
-               current->thread.ppl = ia32_init_pp_list();
-       }
-
-       return ret;
-}
-
-static void
-elf32_set_personality (void)
-{
-       set_personality(PER_LINUX32);
-       current->thread.map_base  = IA32_PAGE_OFFSET/3;
-}
-
-static unsigned long
-elf32_map(struct file *filep, unsigned long addr, struct elf_phdr *eppnt,
-               int prot, int type, unsigned long unused)
-{
-       unsigned long pgoff = (eppnt->p_vaddr) & ~IA32_PAGE_MASK;
-
-       return ia32_do_mmap(filep, (addr & IA32_PAGE_MASK), eppnt->p_filesz + pgoff, prot, type,
-                           eppnt->p_offset - pgoff);
-}
-
-#define cpu_uses_ia32el()      (local_cpu_data->family > 0x1f)
-
-static int __init check_elf32_binfmt(void)
-{
-       if (cpu_uses_ia32el()) {
-               printk("Please use IA-32 EL for executing IA-32 binaries\n");
-               unregister_binfmt(&elf_format);
-       }
-       return 0;
-}
-
-module_init(check_elf32_binfmt)
diff --git a/arch/ia64/ia32/elfcore32.h b/arch/ia64/ia32/elfcore32.h
deleted file mode 100644 (file)
index 6577257..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * IA-32 ELF core dump support.
- *
- * Copyright (C) 2003 Arun Sharma <arun.sharma@intel.com>
- *
- * Derived from the x86_64 version
- */
-#ifndef _ELFCORE32_H_
-#define _ELFCORE32_H_
-
-#include <asm/intrinsics.h>
-#include <asm/uaccess.h>
-
-/* Override elfcore.h */
-#define _LINUX_ELFCORE_H 1
-typedef unsigned int elf_greg_t;
-
-#define ELF_NGREG (sizeof (struct user_regs_struct32) / sizeof(elf_greg_t))
-typedef elf_greg_t elf_gregset_t[ELF_NGREG];
-
-typedef struct ia32_user_i387_struct elf_fpregset_t;
-typedef struct ia32_user_fxsr_struct elf_fpxregset_t;
-
-struct elf_siginfo
-{
-       int     si_signo;                       /* signal number */
-       int     si_code;                        /* extra code */
-       int     si_errno;                       /* errno */
-};
-
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
-/*
- * Hacks are here since types between compat_timeval (= pair of s32) and
- * ia64-native timeval (= pair of s64) are not compatible, at least a file
- * arch/ia64/ia32/../../../fs/binfmt_elf.c will get warnings from compiler on
- * use of cputime_to_timeval(), which usually an alias of jiffies_to_timeval().
- */
-#define cputime_to_timeval(a,b) \
-       do { (b)->tv_usec = 0; (b)->tv_sec = (a)/NSEC_PER_SEC; } while(0)
-#else
-#define jiffies_to_timeval(a,b) \
-       do { (b)->tv_usec = 0; (b)->tv_sec = (a)/HZ; } while(0)
-#endif
-
-struct elf_prstatus
-{
-       struct elf_siginfo pr_info;     /* Info associated with signal */
-       short   pr_cursig;              /* Current signal */
-       unsigned int pr_sigpend;        /* Set of pending signals */
-       unsigned int pr_sighold;        /* Set of held signals */
-       pid_t   pr_pid;
-       pid_t   pr_ppid;
-       pid_t   pr_pgrp;
-       pid_t   pr_sid;
-       struct compat_timeval pr_utime; /* User time */
-       struct compat_timeval pr_stime; /* System time */
-       struct compat_timeval pr_cutime;        /* Cumulative user time */
-       struct compat_timeval pr_cstime;        /* Cumulative system time */
-       elf_gregset_t pr_reg;   /* GP registers */
-       int pr_fpvalid;         /* True if math co-processor being used.  */
-};
-
-#define ELF_PRARGSZ    (80)    /* Number of chars for args */
-
-struct elf_prpsinfo
-{
-       char    pr_state;       /* numeric process state */
-       char    pr_sname;       /* char for pr_state */
-       char    pr_zomb;        /* zombie */
-       char    pr_nice;        /* nice val */
-       unsigned int pr_flag;   /* flags */
-       __u16   pr_uid;
-       __u16   pr_gid;
-       pid_t   pr_pid, pr_ppid, pr_pgrp, pr_sid;
-       /* Lots missing */
-       char    pr_fname[16];   /* filename of executable */
-       char    pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
-};
-
-#define ELF_CORE_COPY_REGS(pr_reg, regs)                       \
-       pr_reg[0] = regs->r11;                          \
-       pr_reg[1] = regs->r9;                           \
-       pr_reg[2] = regs->r10;                          \
-       pr_reg[3] = regs->r14;                          \
-       pr_reg[4] = regs->r15;                          \
-       pr_reg[5] = regs->r13;                          \
-       pr_reg[6] = regs->r8;                           \
-       pr_reg[7] = regs->r16 & 0xffff;                 \
-       pr_reg[8] = (regs->r16 >> 16) & 0xffff;         \
-       pr_reg[9] = (regs->r16 >> 32) & 0xffff;         \
-       pr_reg[10] = (regs->r16 >> 48) & 0xffff;        \
-       pr_reg[11] = regs->r1;                          \
-       pr_reg[12] = regs->cr_iip;                      \
-       pr_reg[13] = regs->r17 & 0xffff;                \
-       pr_reg[14] = ia64_getreg(_IA64_REG_AR_EFLAG);   \
-       pr_reg[15] = regs->r12;                         \
-       pr_reg[16] = (regs->r17 >> 16) & 0xffff;
-
-static inline void elf_core_copy_regs(elf_gregset_t *elfregs,
-                                     struct pt_regs *regs)
-{
-       ELF_CORE_COPY_REGS((*elfregs), regs)
-}
-
-static inline int elf_core_copy_task_regs(struct task_struct *t,
-                                         elf_gregset_t* elfregs)
-{
-       ELF_CORE_COPY_REGS((*elfregs), task_pt_regs(t));
-       return 1;
-}
-
-static inline int
-elf_core_copy_task_fpregs(struct task_struct *tsk, struct pt_regs *regs, elf_fpregset_t *fpu)
-{
-       struct ia32_user_i387_struct *fpstate = (void*)fpu;
-       mm_segment_t old_fs;
-
-       if (!tsk_used_math(tsk))
-               return 0;
-       
-       old_fs = get_fs();
-       set_fs(KERNEL_DS);
-       save_ia32_fpstate(tsk, (struct ia32_user_i387_struct __user *) fpstate);
-       set_fs(old_fs);
-
-       return 1;
-}
-
-#define ELF_CORE_COPY_XFPREGS 1
-#define ELF_CORE_XFPREG_TYPE NT_PRXFPREG
-static inline int
-elf_core_copy_task_xfpregs(struct task_struct *tsk, elf_fpxregset_t *xfpu)
-{
-       struct ia32_user_fxsr_struct *fpxstate = (void*) xfpu;
-       mm_segment_t old_fs;
-
-       if (!tsk_used_math(tsk))
-               return 0;
-
-       old_fs = get_fs();
-       set_fs(KERNEL_DS);
-       save_ia32_fpxstate(tsk, (struct ia32_user_fxsr_struct __user *) fpxstate);
-       set_fs(old_fs);
-
-       return 1;
-}
-
-#endif /* _ELFCORE32_H_ */
diff --git a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S
deleted file mode 100644 (file)
index 2fd7479..0000000
+++ /dev/null
@@ -1,468 +0,0 @@
-#include <asm/asmmacro.h>
-#include <asm/ia32.h>
-#include <asm/asm-offsets.h>
-#include <asm/signal.h>
-#include <asm/thread_info.h>
-
-#include "../kernel/minstate.h"
-
-       /*
-        * execve() is special because in case of success, we need to
-        * setup a null register window frame (in case an IA-32 process
-        * is exec'ing an IA-64 program).
-        */
-ENTRY(ia32_execve)
-       .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(3)
-       alloc loc1=ar.pfs,3,2,4,0
-       mov loc0=rp
-       .body
-       zxt4 out0=in0                   // filename
-       ;;                              // stop bit between alloc and call
-       zxt4 out1=in1                   // argv
-       zxt4 out2=in2                   // envp
-       add out3=16,sp                  // regs
-       br.call.sptk.few rp=sys32_execve
-1:     cmp.ge p6,p0=r8,r0
-       mov ar.pfs=loc1                 // restore ar.pfs
-       ;;
-(p6)   mov ar.pfs=r0                   // clear ar.pfs in case of success
-       sxt4 r8=r8                      // return 64-bit result
-       mov rp=loc0
-       br.ret.sptk.few rp
-END(ia32_execve)
-
-ENTRY(ia32_clone)
-       .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5)
-       alloc r16=ar.pfs,5,2,6,0
-       DO_SAVE_SWITCH_STACK
-       mov loc0=rp
-       mov loc1=r16                            // save ar.pfs across do_fork
-       .body
-       zxt4 out1=in1                           // newsp
-       mov out3=16                             // stacksize (compensates for 16-byte scratch area)
-       adds out2=IA64_SWITCH_STACK_SIZE+16,sp  // out2 = &regs
-       mov out0=in0                            // out0 = clone_flags
-       zxt4 out4=in2                           // out4 = parent_tidptr
-       zxt4 out5=in4                           // out5 = child_tidptr
-       br.call.sptk.many rp=do_fork
-.ret0: .restore sp
-       adds sp=IA64_SWITCH_STACK_SIZE,sp       // pop the switch stack
-       mov ar.pfs=loc1
-       mov rp=loc0
-       br.ret.sptk.many rp
-END(ia32_clone)
-
-GLOBAL_ENTRY(ia32_ret_from_clone)
-       PT_REGS_UNWIND_INFO(0)
-{      /*
-        * Some versions of gas generate bad unwind info if the first instruction of a
-        * procedure doesn't go into the first slot of a bundle.  This is a workaround.
-        */
-       nop.m 0
-       nop.i 0
-       /*
-        * We need to call schedule_tail() to complete the scheduling process.
-        * Called by ia64_switch_to after do_fork()->copy_thread().  r8 contains the
-        * address of the previously executing task.
-        */
-       br.call.sptk.many rp=ia64_invoke_schedule_tail
-}
-.ret1:
-       adds r2=TI_FLAGS+IA64_TASK_SIZE,r13
-       ;;
-       ld4 r2=[r2]
-       ;;
-       mov r8=0
-       and r2=_TIF_SYSCALL_TRACEAUDIT,r2
-       ;;
-       cmp.ne p6,p0=r2,r0
-(p6)   br.cond.spnt .ia32_strace_check_retval
-       ;;                                      // prevent RAW on r8
-END(ia32_ret_from_clone)
-       // fall through
-GLOBAL_ENTRY(ia32_ret_from_syscall)
-       PT_REGS_UNWIND_INFO(0)
-
-       cmp.ge p6,p7=r8,r0                      // syscall executed successfully?
-       adds r2=IA64_PT_REGS_R8_OFFSET+16,sp    // r2 = &pt_regs.r8
-       ;;
-       alloc r3=ar.pfs,0,0,0,0                 // drop the syscall argument frame
-       st8 [r2]=r8                             // store return value in slot for r8
-       br.cond.sptk.many ia64_leave_kernel
-END(ia32_ret_from_syscall)
-
-       //
-       // Invoke a system call, but do some tracing before and after the call.
-       // We MUST preserve the current register frame throughout this routine
-       // because some system calls (such as ia64_execve) directly
-       // manipulate ar.pfs.
-       //
-       // Input:
-       //      r8 = syscall number
-       //      b6 = syscall entry point
-       //
-GLOBAL_ENTRY(ia32_trace_syscall)
-       PT_REGS_UNWIND_INFO(0)
-       mov r3=-38
-       adds r2=IA64_PT_REGS_R8_OFFSET+16,sp
-       ;;
-       st8 [r2]=r3                             // initialize return code to -ENOSYS
-       br.call.sptk.few rp=syscall_trace_enter // give parent a chance to catch syscall args
-       cmp.lt p6,p0=r8,r0                      // check tracehook
-       adds r2=IA64_PT_REGS_R8_OFFSET+16,sp    // r2 = &pt_regs.r8
-       ;;
-(p6)   st8.spill [r2]=r8                       // store return value in slot for r8
-(p6)   br.spnt.few .ret4
-.ret2: // Need to reload arguments (they may be changed by the tracing process)
-       adds r2=IA64_PT_REGS_R1_OFFSET+16,sp    // r2 = &pt_regs.r1
-       adds r3=IA64_PT_REGS_R13_OFFSET+16,sp   // r3 = &pt_regs.r13
-       mov r15=IA32_NR_syscalls
-       ;;
-       ld4 r8=[r2],IA64_PT_REGS_R9_OFFSET-IA64_PT_REGS_R1_OFFSET
-       movl r16=ia32_syscall_table
-       ;;
-       ld4 r33=[r2],8                          // r9 == ecx
-       ld4 r37=[r3],16                         // r13 == ebp
-       cmp.ltu.unc p6,p7=r8,r15
-       ;;
-       ld4 r34=[r2],8                          // r10 == edx
-       ld4 r36=[r3],8                          // r15 == edi
-(p6)   shladd r16=r8,3,r16     // force ni_syscall if not valid syscall number
-       ;;
-       ld8 r16=[r16]
-       ;;
-       ld4 r32=[r2],8                          // r11 == ebx
-       mov b6=r16
-       ld4 r35=[r3],8                          // r14 == esi
-       br.call.sptk.few rp=b6                  // do the syscall
-.ia32_strace_check_retval:
-       cmp.lt p6,p0=r8,r0                      // syscall failed?
-       adds r2=IA64_PT_REGS_R8_OFFSET+16,sp    // r2 = &pt_regs.r8
-       ;;
-       st8.spill [r2]=r8                       // store return value in slot for r8
-       br.call.sptk.few rp=syscall_trace_leave // give parent a chance to catch return value
-.ret4: alloc r2=ar.pfs,0,0,0,0                 // drop the syscall argument frame
-       br.cond.sptk.many ia64_leave_kernel
-END(ia32_trace_syscall)
-
-GLOBAL_ENTRY(sys32_vfork)
-       alloc r16=ar.pfs,2,2,4,0;;
-       mov out0=IA64_CLONE_VFORK|IA64_CLONE_VM|SIGCHLD // out0 = clone_flags
-       br.cond.sptk.few .fork1                 // do the work
-END(sys32_vfork)
-
-GLOBAL_ENTRY(sys32_fork)
-       .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)
-       alloc r16=ar.pfs,2,2,4,0
-       mov out0=SIGCHLD                        // out0 = clone_flags
-       ;;
-.fork1:
-       mov loc0=rp
-       mov loc1=r16                            // save ar.pfs across do_fork
-       DO_SAVE_SWITCH_STACK
-
-       .body
-
-       mov out1=0
-       mov out3=0
-       adds out2=IA64_SWITCH_STACK_SIZE+16,sp  // out2 = &regs
-       br.call.sptk.few rp=do_fork
-.ret5: .restore sp
-       adds sp=IA64_SWITCH_STACK_SIZE,sp       // pop the switch stack
-       mov ar.pfs=loc1
-       mov rp=loc0
-       br.ret.sptk.many rp
-END(sys32_fork)
-
-       .rodata
-       .align 8
-       .globl ia32_syscall_table
-ia32_syscall_table:
-       data8 sys_ni_syscall      /* 0  -  old "setup(" system call*/
-       data8 sys_exit
-       data8 sys32_fork
-       data8 sys_read
-       data8 sys_write
-       data8 compat_sys_open     /* 5 */
-       data8 sys_close
-       data8 sys32_waitpid
-       data8 sys_creat
-       data8 sys_link
-       data8 sys_unlink          /* 10 */
-       data8 ia32_execve
-       data8 sys_chdir
-       data8 compat_sys_time
-       data8 sys_mknod
-       data8 sys_chmod           /* 15 */
-       data8 sys_lchown        /* 16-bit version */
-       data8 sys_ni_syscall      /* old break syscall holder */
-       data8 sys_ni_syscall
-       data8 sys32_lseek
-       data8 sys_getpid          /* 20 */
-       data8 compat_sys_mount
-       data8 sys_oldumount
-       data8 sys_setuid        /* 16-bit version */
-       data8 sys_getuid        /* 16-bit version */
-       data8 compat_sys_stime    /* 25 */
-       data8 compat_sys_ptrace
-       data8 sys32_alarm
-       data8 sys_ni_syscall
-       data8 sys_pause
-       data8 compat_sys_utime    /* 30 */
-       data8 sys_ni_syscall      /* old stty syscall holder */
-       data8 sys_ni_syscall      /* old gtty syscall holder */
-       data8 sys_access
-       data8 sys_nice
-       data8 sys_ni_syscall      /* 35 */        /* old ftime syscall holder */
-       data8 sys_sync
-       data8 sys_kill
-       data8 sys_rename
-       data8 sys_mkdir
-       data8 sys_rmdir           /* 40 */
-       data8 sys_dup
-       data8 sys_ia64_pipe
-       data8 compat_sys_times
-       data8 sys_ni_syscall      /* old prof syscall holder */
-       data8 sys32_brk           /* 45 */
-       data8 sys_setgid        /* 16-bit version */
-       data8 sys_getgid        /* 16-bit version */
-       data8 sys32_signal
-       data8 sys_geteuid       /* 16-bit version */
-       data8 sys_getegid       /* 16-bit version */      /* 50 */
-       data8 sys_acct
-       data8 sys_umount          /* recycled never used phys( */
-       data8 sys_ni_syscall      /* old lock syscall holder */
-       data8 compat_sys_ioctl
-       data8 compat_sys_fcntl    /* 55 */
-       data8 sys_ni_syscall      /* old mpx syscall holder */
-       data8 sys_setpgid
-       data8 sys_ni_syscall      /* old ulimit syscall holder */
-       data8 sys_ni_syscall
-       data8 sys_umask           /* 60 */
-       data8 sys_chroot
-       data8 compat_sys_ustat
-       data8 sys_dup2
-       data8 sys_getppid
-       data8 sys_getpgrp         /* 65 */
-       data8 sys_setsid
-       data8 sys32_sigaction
-       data8 sys_ni_syscall
-       data8 sys_ni_syscall
-       data8 sys_setreuid      /* 16-bit version */      /* 70 */
-       data8 sys_setregid      /* 16-bit version */
-       data8 sys32_sigsuspend
-       data8 compat_sys_sigpending
-       data8 sys_sethostname
-       data8 compat_sys_setrlimit        /* 75 */
-       data8 compat_sys_old_getrlimit
-       data8 compat_sys_getrusage
-       data8 compat_sys_gettimeofday
-       data8 compat_sys_settimeofday
-       data8 sys32_getgroups16   /* 80 */
-       data8 sys32_setgroups16
-       data8 sys32_old_select
-       data8 sys_symlink
-       data8 sys_ni_syscall
-       data8 sys_readlink        /* 85 */
-       data8 sys_uselib
-       data8 sys_swapon
-       data8 sys_reboot
-       data8 compat_sys_old_readdir
-       data8 sys32_mmap          /* 90 */
-       data8 sys32_munmap
-       data8 sys_truncate
-       data8 sys_ftruncate
-       data8 sys_fchmod
-       data8 sys_fchown        /* 16-bit version */      /* 95 */
-       data8 sys_getpriority
-       data8 sys_setpriority
-       data8 sys_ni_syscall      /* old profil syscall holder */
-       data8 compat_sys_statfs
-       data8 compat_sys_fstatfs          /* 100 */
-       data8 sys_ni_syscall    /* ioperm */
-       data8 compat_sys_socketcall
-       data8 sys_syslog
-       data8 compat_sys_setitimer
-       data8 compat_sys_getitimer        /* 105 */
-       data8 compat_sys_newstat
-       data8 compat_sys_newlstat
-       data8 compat_sys_newfstat
-       data8 sys_ni_syscall
-       data8 sys_ni_syscall    /* iopl */      /* 110 */
-       data8 sys_vhangup
-       data8 sys_ni_syscall            /* used to be sys_idle */
-       data8 sys_ni_syscall
-       data8 compat_sys_wait4
-       data8 sys_swapoff         /* 115 */
-       data8 compat_sys_sysinfo
-       data8 sys32_ipc
-       data8 sys_fsync
-       data8 sys32_sigreturn
-       data8 ia32_clone          /* 120 */
-       data8 sys_setdomainname
-       data8 sys32_newuname
-       data8 sys32_modify_ldt
-       data8 compat_sys_adjtimex
-       data8 sys32_mprotect      /* 125 */
-       data8 compat_sys_sigprocmask
-       data8 sys_ni_syscall    /* create_module */
-       data8 sys_ni_syscall    /* init_module */
-       data8 sys_ni_syscall    /* delete_module */
-       data8 sys_ni_syscall    /* get_kernel_syms */  /* 130 */
-       data8 sys32_quotactl
-       data8 sys_getpgid
-       data8 sys_fchdir
-       data8 sys_ni_syscall    /* sys_bdflush */
-       data8 sys_sysfs         /* 135 */
-       data8 sys32_personality
-       data8 sys_ni_syscall      /* for afs_syscall */
-       data8 sys_setfsuid      /* 16-bit version */
-       data8 sys_setfsgid      /* 16-bit version */
-       data8 sys_llseek          /* 140 */
-       data8 compat_sys_getdents
-       data8 compat_sys_select
-       data8 sys_flock
-       data8 sys32_msync
-       data8 compat_sys_readv    /* 145 */
-       data8 compat_sys_writev
-       data8 sys_getsid
-       data8 sys_fdatasync
-       data8 compat_sys_sysctl
-       data8 sys_mlock           /* 150 */
-       data8 sys_munlock
-       data8 sys_mlockall
-       data8 sys_munlockall
-       data8 sys_sched_setparam
-       data8 sys_sched_getparam  /* 155 */
-       data8 sys_sched_setscheduler
-       data8 sys_sched_getscheduler
-       data8 sys_sched_yield
-       data8 sys_sched_get_priority_max
-       data8 sys_sched_get_priority_min         /* 160 */
-       data8 sys32_sched_rr_get_interval
-       data8 compat_sys_nanosleep
-       data8 sys32_mremap
-       data8 sys_setresuid     /* 16-bit version */
-       data8 sys32_getresuid16 /* 16-bit version */      /* 165 */
-       data8 sys_ni_syscall    /* vm86 */
-       data8 sys_ni_syscall    /* sys_query_module */
-       data8 sys_poll
-       data8 sys_ni_syscall    /* nfsservctl */
-       data8 sys_setresgid       /* 170 */
-       data8 sys32_getresgid16
-       data8 sys_prctl
-       data8 sys32_rt_sigreturn
-       data8 sys32_rt_sigaction
-       data8 sys32_rt_sigprocmask /* 175 */
-       data8 sys_rt_sigpending
-       data8 compat_sys_rt_sigtimedwait
-       data8 sys32_rt_sigqueueinfo
-       data8 compat_sys_rt_sigsuspend
-       data8 sys32_pread         /* 180 */
-       data8 sys32_pwrite
-       data8 sys_chown /* 16-bit version */
-       data8 sys_getcwd
-       data8 sys_capget
-       data8 sys_capset          /* 185 */
-       data8 sys32_sigaltstack
-       data8 sys32_sendfile
-       data8 sys_ni_syscall              /* streams1 */
-       data8 sys_ni_syscall              /* streams2 */
-       data8 sys32_vfork         /* 190 */
-       data8 compat_sys_getrlimit
-       data8 sys32_mmap2
-       data8 sys32_truncate64
-       data8 sys32_ftruncate64
-       data8 sys32_stat64        /* 195 */
-       data8 sys32_lstat64
-       data8 sys32_fstat64
-       data8 sys_lchown
-       data8 sys_getuid
-       data8 sys_getgid          /* 200 */
-       data8 sys_geteuid
-       data8 sys_getegid
-       data8 sys_setreuid
-       data8 sys_setregid
-       data8 sys_getgroups       /* 205 */
-       data8 sys_setgroups
-       data8 sys_fchown
-       data8 sys_setresuid
-       data8 sys_getresuid
-       data8 sys_setresgid       /* 210 */
-       data8 sys_getresgid
-       data8 sys_chown
-       data8 sys_setuid
-       data8 sys_setgid
-       data8 sys_setfsuid        /* 215 */
-       data8 sys_setfsgid
-       data8 sys_pivot_root
-       data8 sys_mincore
-       data8 sys_madvise
-       data8 compat_sys_getdents64       /* 220 */
-       data8 compat_sys_fcntl64
-       data8 sys_ni_syscall            /* reserved for TUX */
-       data8 sys_ni_syscall            /* reserved for Security */
-       data8 sys_gettid
-       data8 sys_readahead       /* 225 */
-       data8 sys_setxattr
-       data8 sys_lsetxattr
-       data8 sys_fsetxattr
-       data8 sys_getxattr
-       data8 sys_lgetxattr     /* 230 */
-       data8 sys_fgetxattr
-       data8 sys_listxattr
-       data8 sys_llistxattr
-       data8 sys_flistxattr
-       data8 sys_removexattr   /* 235 */
-       data8 sys_lremovexattr
-       data8 sys_fremovexattr
-       data8 sys_tkill
-       data8 sys_sendfile64
-       data8 compat_sys_futex  /* 240 */
-       data8 compat_sys_sched_setaffinity
-       data8 compat_sys_sched_getaffinity
-       data8 sys32_set_thread_area
-       data8 sys32_get_thread_area
-       data8 compat_sys_io_setup       /* 245 */
-       data8 sys_io_destroy
-       data8 compat_sys_io_getevents
-       data8 compat_sys_io_submit
-       data8 sys_io_cancel
-       data8 sys_fadvise64     /* 250 */
-       data8 sys_ni_syscall
-       data8 sys_exit_group
-       data8 sys_lookup_dcookie
-       data8 sys_epoll_create
-       data8 sys32_epoll_ctl   /* 255 */
-       data8 sys32_epoll_wait
-       data8 sys_remap_file_pages
-       data8 sys_set_tid_address
-       data8 compat_sys_timer_create
-       data8 compat_sys_timer_settime  /* 260 */
-       data8 compat_sys_timer_gettime
-       data8 sys_timer_getoverrun
-       data8 sys_timer_delete
-       data8 compat_sys_clock_settime
-       data8 compat_sys_clock_gettime /* 265 */
-       data8 compat_sys_clock_getres
-       data8 compat_sys_clock_nanosleep
-       data8 compat_sys_statfs64
-       data8 compat_sys_fstatfs64
-       data8 sys_tgkill        /* 270 */
-       data8 compat_sys_utimes
-       data8 sys32_fadvise64_64
-       data8 sys_ni_syscall
-       data8 sys_ni_syscall
-       data8 sys_ni_syscall    /* 275 */
-       data8 sys_ni_syscall
-       data8 compat_sys_mq_open
-       data8 sys_mq_unlink
-       data8 compat_sys_mq_timedsend
-       data8 compat_sys_mq_timedreceive        /* 280 */
-       data8 compat_sys_mq_notify
-       data8 compat_sys_mq_getsetattr
-       data8 sys_ni_syscall            /* reserved for kexec */
-       data8 compat_sys_waitid
-
-       // guard against failures to increase IA32_NR_syscalls
-       .org ia32_syscall_table + 8*IA32_NR_syscalls
diff --git a/arch/ia64/ia32/ia32_ldt.c b/arch/ia64/ia32/ia32_ldt.c
deleted file mode 100644 (file)
index 16d51c1..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2001, 2004 Hewlett-Packard Co
- *     David Mosberger-Tang <davidm@hpl.hp.com>
- *
- * Adapted from arch/i386/kernel/ldt.c
- */
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/vmalloc.h>
-
-#include <asm/uaccess.h>
-
-#include "ia32priv.h"
-
-/*
- * read_ldt() is not really atomic - this is not a problem since synchronization of reads
- * and writes done to the LDT has to be assured by user-space anyway. Writes are atomic,
- * to protect the security checks done on new descriptors.
- */
-static int
-read_ldt (void __user *ptr, unsigned long bytecount)
-{
-       unsigned long bytes_left, n;
-       char __user *src, *dst;
-       char buf[256];  /* temporary buffer (don't overflow kernel stack!) */
-
-       if (bytecount > IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE)
-               bytecount = IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE;
-
-       bytes_left = bytecount;
-
-       src = (void __user *) IA32_LDT_OFFSET;
-       dst = ptr;
-
-       while (bytes_left) {
-               n = sizeof(buf);
-               if (n > bytes_left)
-                       n = bytes_left;
-
-               /*
-                * We know we're reading valid memory, but we still must guard against
-                * running out of memory.
-                */
-               if (__copy_from_user(buf, src, n))
-                       return -EFAULT;
-
-               if (copy_to_user(dst, buf, n))
-                       return -EFAULT;
-
-               src += n;
-               dst += n;
-               bytes_left -= n;
-       }
-       return bytecount;
-}
-
-static int
-read_default_ldt (void __user * ptr, unsigned long bytecount)
-{
-       unsigned long size;
-       int err;
-
-       /* XXX fix me: should return equivalent of default_ldt[0] */
-       err = 0;
-       size = 8;
-       if (size > bytecount)
-               size = bytecount;
-
-       err = size;
-       if (clear_user(ptr, size))
-               err = -EFAULT;
-
-       return err;
-}
-
-static int
-write_ldt (void __user * ptr, unsigned long bytecount, int oldmode)
-{
-       struct ia32_user_desc ldt_info;
-       __u64 entry;
-       int ret;
-
-       if (bytecount != sizeof(ldt_info))
-               return -EINVAL;
-       if (copy_from_user(&ldt_info, ptr, sizeof(ldt_info)))
-               return -EFAULT;
-
-       if (ldt_info.entry_number >= IA32_LDT_ENTRIES)
-               return -EINVAL;
-       if (ldt_info.contents == 3) {
-               if (oldmode)
-                       return -EINVAL;
-               if (ldt_info.seg_not_present == 0)
-                       return -EINVAL;
-       }
-
-       if (ldt_info.base_addr == 0 && ldt_info.limit == 0
-           && (oldmode || (ldt_info.contents == 0 && ldt_info.read_exec_only == 1
-                           && ldt_info.seg_32bit == 0 && ldt_info.limit_in_pages == 0
-                           && ldt_info.seg_not_present == 1 && ldt_info.useable == 0)))
-               /* allow LDTs to be cleared by the user */
-               entry = 0;
-       else
-               /* we must set the "Accessed" bit as IVE doesn't emulate it */
-               entry = IA32_SEG_DESCRIPTOR(ldt_info.base_addr, ldt_info.limit,
-                                           (((ldt_info.read_exec_only ^ 1) << 1)
-                                            | (ldt_info.contents << 2)) | 1,
-                                           1, 3, ldt_info.seg_not_present ^ 1,
-                                           (oldmode ? 0 : ldt_info.useable),
-                                           ldt_info.seg_32bit,
-                                           ldt_info.limit_in_pages);
-       /*
-        * Install the new entry.  We know we're accessing valid (mapped) user-level
-        * memory, but we still need to guard against out-of-memory, hence we must use
-        * put_user().
-        */
-       ret = __put_user(entry, (__u64 __user *) IA32_LDT_OFFSET + ldt_info.entry_number);
-       ia32_load_segment_descriptors(current);
-       return ret;
-}
-
-asmlinkage int
-sys32_modify_ldt (int func, unsigned int ptr, unsigned int bytecount)
-{
-       int ret = -ENOSYS;
-
-       switch (func) {
-             case 0:
-               ret = read_ldt(compat_ptr(ptr), bytecount);
-               break;
-             case 1:
-               ret = write_ldt(compat_ptr(ptr), bytecount, 1);
-               break;
-             case 2:
-               ret = read_default_ldt(compat_ptr(ptr), bytecount);
-               break;
-             case 0x11:
-               ret = write_ldt(compat_ptr(ptr), bytecount, 0);
-               break;
-       }
-       return ret;
-}
diff --git a/arch/ia64/ia32/ia32_signal.c b/arch/ia64/ia32/ia32_signal.c
deleted file mode 100644 (file)
index b763ca1..0000000
+++ /dev/null
@@ -1,1010 +0,0 @@
-/*
- * IA32 Architecture-specific signal handling support.
- *
- * Copyright (C) 1999, 2001-2002, 2005 Hewlett-Packard Co
- *     David Mosberger-Tang <davidm@hpl.hp.com>
- * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com>
- * Copyright (C) 2000 VA Linux Co
- * Copyright (C) 2000 Don Dugger <n0ano@valinux.com>
- *
- * Derived from i386 and Alpha versions.
- */
-
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/personality.h>
-#include <linux/ptrace.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/smp.h>
-#include <linux/stddef.h>
-#include <linux/syscalls.h>
-#include <linux/unistd.h>
-#include <linux/wait.h>
-#include <linux/compat.h>
-
-#include <asm/intrinsics.h>
-#include <asm/uaccess.h>
-#include <asm/rse.h>
-#include <asm/sigcontext.h>
-
-#include "ia32priv.h"
-
-#include "../kernel/sigframe.h"
-
-#define A(__x)         ((unsigned long)(__x))
-
-#define DEBUG_SIG      0
-#define _BLOCKABLE     (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-
-#define __IA32_NR_sigreturn            119
-#define __IA32_NR_rt_sigreturn         173
-
-struct sigframe_ia32
-{
-       int pretcode;
-       int sig;
-       struct sigcontext_ia32 sc;
-       struct _fpstate_ia32 fpstate;
-       unsigned int extramask[_COMPAT_NSIG_WORDS-1];
-       char retcode[8];
-};
-
-struct rt_sigframe_ia32
-{
-       int pretcode;
-       int sig;
-       int pinfo;
-       int puc;
-       compat_siginfo_t info;
-       struct ucontext_ia32 uc;
-       struct _fpstate_ia32 fpstate;
-       char retcode[8];
-};
-
-int
-copy_siginfo_from_user32 (siginfo_t *to, compat_siginfo_t __user *from)
-{
-       unsigned long tmp;
-       int err;
-
-       if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))
-               return -EFAULT;
-
-       err = __get_user(to->si_signo, &from->si_signo);
-       err |= __get_user(to->si_errno, &from->si_errno);
-       err |= __get_user(to->si_code, &from->si_code);
-
-       if (to->si_code < 0)
-               err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
-       else {
-               switch (to->si_code >> 16) {
-                     case __SI_CHLD >> 16:
-                       err |= __get_user(to->si_utime, &from->si_utime);
-                       err |= __get_user(to->si_stime, &from->si_stime);
-                       err |= __get_user(to->si_status, &from->si_status);
-                     default:
-                       err |= __get_user(to->si_pid, &from->si_pid);
-                       err |= __get_user(to->si_uid, &from->si_uid);
-                       break;
-                     case __SI_FAULT >> 16:
-                       err |= __get_user(tmp, &from->si_addr);
-                       to->si_addr = (void __user *) tmp;
-                       break;
-                     case __SI_POLL >> 16:
-                       err |= __get_user(to->si_band, &from->si_band);
-                       err |= __get_user(to->si_fd, &from->si_fd);
-                       break;
-                     case __SI_RT >> 16: /* This is not generated by the kernel as of now.  */
-                     case __SI_MESGQ >> 16:
-                       err |= __get_user(to->si_pid, &from->si_pid);
-                       err |= __get_user(to->si_uid, &from->si_uid);
-                       err |= __get_user(to->si_int, &from->si_int);
-                       break;
-               }
-       }
-       return err;
-}
-
-int
-copy_siginfo_to_user32 (compat_siginfo_t __user *to, siginfo_t *from)
-{
-       unsigned int addr;
-       int err;
-
-       if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
-               return -EFAULT;
-
-       /* If you change siginfo_t structure, please be sure
-          this code is fixed accordingly.
-          It should never copy any pad contained in the structure
-          to avoid security leaks, but must copy the generic
-          3 ints plus the relevant union member.
-          This routine must convert siginfo from 64bit to 32bit as well
-          at the same time.  */
-       err = __put_user(from->si_signo, &to->si_signo);
-       err |= __put_user(from->si_errno, &to->si_errno);
-       err |= __put_user((short)from->si_code, &to->si_code);
-       if (from->si_code < 0)
-               err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
-       else {
-               switch (from->si_code >> 16) {
-               case __SI_CHLD >> 16:
-                       err |= __put_user(from->si_utime, &to->si_utime);
-                       err |= __put_user(from->si_stime, &to->si_stime);
-                       err |= __put_user(from->si_status, &to->si_status);
-               default:
-                       err |= __put_user(from->si_pid, &to->si_pid);
-                       err |= __put_user(from->si_uid, &to->si_uid);
-                       break;
-               case __SI_FAULT >> 16:
-                       /* avoid type-checking warnings by copying _pad[0] in lieu of si_addr... */
-                       err |= __put_user(from->_sifields._pad[0], &to->si_addr);
-                       break;
-               case __SI_POLL >> 16:
-                       err |= __put_user(from->si_band, &to->si_band);
-                       err |= __put_user(from->si_fd, &to->si_fd);
-                       break;
-               case __SI_TIMER >> 16:
-                       err |= __put_user(from->si_tid, &to->si_tid);
-                       err |= __put_user(from->si_overrun, &to->si_overrun);
-                       addr = (unsigned long) from->si_ptr;
-                       err |= __put_user(addr, &to->si_ptr);
-                       break;
-               case __SI_RT >> 16:     /* Not generated by the kernel as of now.  */
-               case __SI_MESGQ >> 16:
-                       err |= __put_user(from->si_uid, &to->si_uid);
-                       err |= __put_user(from->si_pid, &to->si_pid);
-                       addr = (unsigned long) from->si_ptr;
-                       err |= __put_user(addr, &to->si_ptr);
-                       break;
-               }
-       }
-       return err;
-}
-
-
-/*
- *  SAVE and RESTORE of ia32 fpstate info, from ia64 current state
- *  Used in exception handler to pass the fpstate to the user, and restore
- *  the fpstate while returning from the exception handler.
- *
- *    fpstate info and their mapping to IA64 regs:
- *    fpstate    REG(BITS)      Attribute    Comments
- *    cw         ar.fcr(0:12)                with bits 7 and 6 not used
- *    sw         ar.fsr(0:15)
- *    tag        ar.fsr(16:31)               with odd numbered bits not used
- *                                           (read returns 0, writes ignored)
- *    ipoff      ar.fir(0:31)
- *    cssel      ar.fir(32:47)
- *    dataoff    ar.fdr(0:31)
- *    datasel    ar.fdr(32:47)
- *
- *    _st[(0+TOS)%8]   f8
- *    _st[(1+TOS)%8]   f9
- *    _st[(2+TOS)%8]   f10
- *    _st[(3+TOS)%8]   f11                   (f8..f11 from ptregs)
- *      : :            :                     (f12..f15 from live reg)
- *      : :            :
- *    _st[(7+TOS)%8]   f15                   TOS=sw.top(bits11:13)
- *
- *    status     Same as sw     RO
- *    magic      0                           as X86_FXSR_MAGIC in ia32
- *    mxcsr      Bits(7:15)=ar.fcr(39:47)
- *               Bits(0:5) =ar.fsr(32:37)    with bit 6 reserved
- *    _xmm[0..7] f16..f31                    (live registers)
- *                                           with _xmm[0]
- *                                             Bit(64:127)=f17(0:63)
- *                                             Bit(0:63)=f16(0:63)
- *    All other fields unused...
- */
-
-static int
-save_ia32_fpstate_live (struct _fpstate_ia32 __user *save)
-{
-       struct task_struct *tsk = current;
-       struct pt_regs *ptp;
-       struct _fpreg_ia32 *fpregp;
-       char buf[32];
-       unsigned long fsr, fcr, fir, fdr;
-       unsigned long new_fsr;
-       unsigned long num128[2];
-       unsigned long mxcsr=0;
-       int fp_tos, fr8_st_map;
-
-       if (!access_ok(VERIFY_WRITE, save, sizeof(*save)))
-               return -EFAULT;
-
-       /* Read in fsr, fcr, fir, fdr and copy onto fpstate */
-       fsr = ia64_getreg(_IA64_REG_AR_FSR);
-       fcr = ia64_getreg(_IA64_REG_AR_FCR);
-       fir = ia64_getreg(_IA64_REG_AR_FIR);
-       fdr = ia64_getreg(_IA64_REG_AR_FDR);
-
-       /*
-        * We need to clear the exception state before calling the signal handler. Clear
-        * the bits 15, bits 0-7 in fp status word. Similar to the functionality of fnclex
-        * instruction.
-        */
-       new_fsr = fsr & ~0x80ff;
-       ia64_setreg(_IA64_REG_AR_FSR, new_fsr);
-
-       __put_user(fcr & 0xffff, &save->cw);
-       __put_user(fsr & 0xffff, &save->sw);
-       __put_user((fsr>>16) & 0xffff, &save->tag);
-       __put_user(fir, &save->ipoff);
-       __put_user((fir>>32) & 0xffff, &save->cssel);
-       __put_user(fdr, &save->dataoff);
-       __put_user((fdr>>32) & 0xffff, &save->datasel);
-       __put_user(fsr & 0xffff, &save->status);
-
-       mxcsr = ((fcr>>32) & 0xff80) | ((fsr>>32) & 0x3f);
-       __put_user(mxcsr & 0xffff, &save->mxcsr);
-       __put_user( 0, &save->magic); //#define X86_FXSR_MAGIC   0x0000
-
-       /*
-        * save f8..f11  from pt_regs
-        * save f12..f15 from live register set
-        */
-       /*
-        *  Find the location where f8 has to go in fp reg stack.  This depends on
-        *  TOP(11:13) field of sw. Other f reg continue sequentially from where f8 maps
-        *  to.
-        */
-       fp_tos = (fsr>>11)&0x7;
-       fr8_st_map = (8-fp_tos)&0x7;
-       ptp = task_pt_regs(tsk);
-       fpregp = (struct _fpreg_ia32 *)(((unsigned long)buf + 15) & ~15);
-       ia64f2ia32f(fpregp, &ptp->f8);
-       copy_to_user(&save->_st[(0+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
-       ia64f2ia32f(fpregp, &ptp->f9);
-       copy_to_user(&save->_st[(1+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
-       ia64f2ia32f(fpregp, &ptp->f10);
-       copy_to_user(&save->_st[(2+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
-       ia64f2ia32f(fpregp, &ptp->f11);
-       copy_to_user(&save->_st[(3+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
-
-       ia64_stfe(fpregp, 12);
-       copy_to_user(&save->_st[(4+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
-       ia64_stfe(fpregp, 13);
-       copy_to_user(&save->_st[(5+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
-       ia64_stfe(fpregp, 14);
-       copy_to_user(&save->_st[(6+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
-       ia64_stfe(fpregp, 15);
-       copy_to_user(&save->_st[(7+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
-
-       ia64_stf8(&num128[0], 16);
-       ia64_stf8(&num128[1], 17);
-       copy_to_user(&save->_xmm[0], num128, sizeof(struct _xmmreg_ia32));
-
-       ia64_stf8(&num128[0], 18);
-       ia64_stf8(&num128[1], 19);
-       copy_to_user(&save->_xmm[1], num128, sizeof(struct _xmmreg_ia32));
-
-       ia64_stf8(&num128[0], 20);
-       ia64_stf8(&num128[1], 21);
-       copy_to_user(&save->_xmm[2], num128, sizeof(struct _xmmreg_ia32));
-
-       ia64_stf8(&num128[0], 22);
-       ia64_stf8(&num128[1], 23);
-       copy_to_user(&save->_xmm[3], num128, sizeof(struct _xmmreg_ia32));
-
-       ia64_stf8(&num128[0], 24);
-       ia64_stf8(&num128[1], 25);
-       copy_to_user(&save->_xmm[4], num128, sizeof(struct _xmmreg_ia32));
-
-       ia64_stf8(&num128[0], 26);
-       ia64_stf8(&num128[1], 27);
-       copy_to_user(&save->_xmm[5], num128, sizeof(struct _xmmreg_ia32));
-
-       ia64_stf8(&num128[0], 28);
-       ia64_stf8(&num128[1], 29);
-       copy_to_user(&save->_xmm[6], num128, sizeof(struct _xmmreg_ia32));
-
-       ia64_stf8(&num128[0], 30);
-       ia64_stf8(&num128[1], 31);
-       copy_to_user(&save->_xmm[7], num128, sizeof(struct _xmmreg_ia32));
-       return 0;
-}
-
-static int
-restore_ia32_fpstate_live (struct _fpstate_ia32 __user *save)
-{
-       struct task_struct *tsk = current;
-       struct pt_regs *ptp;
-       unsigned int lo, hi;
-       unsigned long num128[2];
-       unsigned long num64, mxcsr;
-       struct _fpreg_ia32 *fpregp;
-       char buf[32];
-       unsigned long fsr, fcr, fir, fdr;
-       int fp_tos, fr8_st_map;
-
-       if (!access_ok(VERIFY_READ, save, sizeof(*save)))
-               return(-EFAULT);
-
-       /*
-        * Updating fsr, fcr, fir, fdr.
-        * Just a bit more complicated than save.
-        * - Need to make sure that we don't write any value other than the
-        *   specific fpstate info
-        * - Need to make sure that the untouched part of frs, fdr, fir, fcr
-        *   should remain same while writing.
-        * So, we do a read, change specific fields and write.
-        */
-       fsr = ia64_getreg(_IA64_REG_AR_FSR);
-       fcr = ia64_getreg(_IA64_REG_AR_FCR);
-       fir = ia64_getreg(_IA64_REG_AR_FIR);
-       fdr = ia64_getreg(_IA64_REG_AR_FDR);
-
-       __get_user(mxcsr, (unsigned int __user *)&save->mxcsr);
-       /* setting bits 0..5 8..12 with cw and 39..47 from mxcsr */
-       __get_user(lo, (unsigned int __user *)&save->cw);
-       num64 = mxcsr & 0xff10;
-       num64 = (num64 << 32) | (lo & 0x1f3f);
-       fcr = (fcr & (~0xff1000001f3fUL)) | num64;
-
-       /* setting bits 0..31 with sw and tag and 32..37 from mxcsr */
-       __get_user(lo, (unsigned int __user *)&save->sw);
-       /* set bits 15,7 (fsw.b, fsw.es) to reflect the current error status */
-       if ( !(lo & 0x7f) )
-               lo &= (~0x8080);
-       __get_user(hi, (unsigned int __user *)&save->tag);
-       num64 = mxcsr & 0x3f;
-       num64 = (num64 << 16) | (hi & 0xffff);
-       num64 = (num64 << 16) | (lo & 0xffff);
-       fsr = (fsr & (~0x3fffffffffUL)) | num64;
-
-       /* setting bits 0..47 with cssel and ipoff */
-       __get_user(lo, (unsigned int __user *)&save->ipoff);
-       __get_user(hi, (unsigned int __user *)&save->cssel);
-       num64 = hi & 0xffff;
-       num64 = (num64 << 32) | lo;
-       fir = (fir & (~0xffffffffffffUL)) | num64;
-
-       /* setting bits 0..47 with datasel and dataoff */
-       __get_user(lo, (unsigned int __user *)&save->dataoff);
-       __get_user(hi, (unsigned int __user *)&save->datasel);
-       num64 = hi & 0xffff;
-       num64 = (num64 << 32) | lo;
-       fdr = (fdr & (~0xffffffffffffUL)) | num64;
-
-       ia64_setreg(_IA64_REG_AR_FSR, fsr);
-       ia64_setreg(_IA64_REG_AR_FCR, fcr);
-       ia64_setreg(_IA64_REG_AR_FIR, fir);
-       ia64_setreg(_IA64_REG_AR_FDR, fdr);
-
-       /*
-        * restore f8..f11 onto pt_regs
-        * restore f12..f15 onto live registers
-        */
-       /*
-        *  Find the location where f8 has to go in fp reg stack.  This depends on
-        *  TOP(11:13) field of sw. Other f reg continue sequentially from where f8 maps
-        *  to.
-        */
-       fp_tos = (fsr>>11)&0x7;
-       fr8_st_map = (8-fp_tos)&0x7;
-       fpregp = (struct _fpreg_ia32 *)(((unsigned long)buf + 15) & ~15);
-
-       ptp = task_pt_regs(tsk);
-       copy_from_user(fpregp, &save->_st[(0+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
-       ia32f2ia64f(&ptp->f8, fpregp);
-       copy_from_user(fpregp, &save->_st[(1+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
-       ia32f2ia64f(&ptp->f9, fpregp);
-       copy_from_user(fpregp, &save->_st[(2+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
-       ia32f2ia64f(&ptp->f10, fpregp);
-       copy_from_user(fpregp, &save->_st[(3+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
-       ia32f2ia64f(&ptp->f11, fpregp);
-
-       copy_from_user(fpregp, &save->_st[(4+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
-       ia64_ldfe(12, fpregp);
-       copy_from_user(fpregp, &save->_st[(5+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
-       ia64_ldfe(13, fpregp);
-       copy_from_user(fpregp, &save->_st[(6+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
-       ia64_ldfe(14, fpregp);
-       copy_from_user(fpregp, &save->_st[(7+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
-       ia64_ldfe(15, fpregp);
-
-       copy_from_user(num128, &save->_xmm[0], sizeof(struct _xmmreg_ia32));
-       ia64_ldf8(16, &num128[0]);
-       ia64_ldf8(17, &num128[1]);
-
-       copy_from_user(num128, &save->_xmm[1], sizeof(struct _xmmreg_ia32));
-       ia64_ldf8(18, &num128[0]);
-       ia64_ldf8(19, &num128[1]);
-
-       copy_from_user(num128, &save->_xmm[2], sizeof(struct _xmmreg_ia32));
-       ia64_ldf8(20, &num128[0]);
-       ia64_ldf8(21, &num128[1]);
-
-       copy_from_user(num128, &save->_xmm[3], sizeof(struct _xmmreg_ia32));
-       ia64_ldf8(22, &num128[0]);
-       ia64_ldf8(23, &num128[1]);
-
-       copy_from_user(num128, &save->_xmm[4], sizeof(struct _xmmreg_ia32));
-       ia64_ldf8(24, &num128[0]);
-       ia64_ldf8(25, &num128[1]);
-
-       copy_from_user(num128, &save->_xmm[5], sizeof(struct _xmmreg_ia32));
-       ia64_ldf8(26, &num128[0]);
-       ia64_ldf8(27, &num128[1]);
-
-       copy_from_user(num128, &save->_xmm[6], sizeof(struct _xmmreg_ia32));
-       ia64_ldf8(28, &num128[0]);
-       ia64_ldf8(29, &num128[1]);
-
-       copy_from_user(num128, &save->_xmm[7], sizeof(struct _xmmreg_ia32));
-       ia64_ldf8(30, &num128[0]);
-       ia64_ldf8(31, &num128[1]);
-       return 0;
-}
-
-static inline void
-sigact_set_handler (struct k_sigaction *sa, unsigned int handler, unsigned int restorer)
-{
-       if (handler + 1 <= 2)
-               /* SIG_DFL, SIG_IGN, or SIG_ERR: must sign-extend to 64-bits */
-               sa->sa.sa_handler = (__sighandler_t) A((int) handler);
-       else
-               sa->sa.sa_handler = (__sighandler_t) (((unsigned long) restorer << 32) | handler);
-}
-
-asmlinkage long
-sys32_sigsuspend (int history0, int history1, old_sigset_t mask)
-{
-       mask &= _BLOCKABLE;
-       spin_lock_irq(&current->sighand->siglock);
-       current->saved_sigmask = current->blocked;
-       siginitset(&current->blocked, mask);
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
-
-       current->state = TASK_INTERRUPTIBLE;
-       schedule();
-       set_restore_sigmask();
-       return -ERESTARTNOHAND;
-}
-
-asmlinkage long
-sys32_signal (int sig, unsigned int handler)
-{
-       struct k_sigaction new_sa, old_sa;
-       int ret;
-
-       sigact_set_handler(&new_sa, handler, 0);
-       new_sa.sa.sa_flags = SA_ONESHOT | SA_NOMASK;
-       sigemptyset(&new_sa.sa.sa_mask);
-
-       ret = do_sigaction(sig, &new_sa, &old_sa);
-
-       return ret ? ret : IA32_SA_HANDLER(&old_sa);
-}
-
-asmlinkage long
-sys32_rt_sigaction (int sig, struct sigaction32 __user *act,
-                   struct sigaction32 __user *oact, unsigned int sigsetsize)
-{
-       struct k_sigaction new_ka, old_ka;
-       unsigned int handler, restorer;
-       int ret;
-
-       /* XXX: Don't preclude handling different sized sigset_t's.  */
-       if (sigsetsize != sizeof(compat_sigset_t))
-               return -EINVAL;
-
-       if (act) {
-               ret = get_user(handler, &act->sa_handler);
-               ret |= get_user(new_ka.sa.sa_flags, &act->sa_flags);
-               ret |= get_user(restorer, &act->sa_restorer);
-               ret |= copy_from_user(&new_ka.sa.sa_mask, &act->sa_mask, sizeof(compat_sigset_t));
-               if (ret)
-                       return -EFAULT;
-
-               sigact_set_handler(&new_ka, handler, restorer);
-       }
-
-       ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
-       if (!ret && oact) {
-               ret = put_user(IA32_SA_HANDLER(&old_ka), &oact->sa_handler);
-               ret |= put_user(old_ka.sa.sa_flags, &oact->sa_flags);
-               ret |= put_user(IA32_SA_RESTORER(&old_ka), &oact->sa_restorer);
-               ret |= copy_to_user(&oact->sa_mask, &old_ka.sa.sa_mask, sizeof(compat_sigset_t));
-       }
-       return ret;
-}
-
-
-asmlinkage long
-sys32_rt_sigprocmask (int how, compat_sigset_t __user *set, compat_sigset_t __user *oset,
-                     unsigned int sigsetsize)
-{
-       mm_segment_t old_fs = get_fs();
-       sigset_t s;
-       long ret;
-
-       if (sigsetsize > sizeof(s))
-               return -EINVAL;
-
-       if (set) {
-               memset(&s, 0, sizeof(s));
-               if (copy_from_user(&s.sig, set, sigsetsize))
-                       return -EFAULT;
-       }
-       set_fs(KERNEL_DS);
-       ret = sys_rt_sigprocmask(how,
-                                set ? (sigset_t __user *) &s : NULL,
-                                oset ? (sigset_t __user *) &s : NULL, sizeof(s));
-       set_fs(old_fs);
-       if (ret)
-               return ret;
-       if (oset) {
-               if (copy_to_user(oset, &s.sig, sigsetsize))
-                       return -EFAULT;
-       }
-       return 0;
-}
-
-asmlinkage long
-sys32_rt_sigqueueinfo (int pid, int sig, compat_siginfo_t __user *uinfo)
-{
-       mm_segment_t old_fs = get_fs();
-       siginfo_t info;
-       int ret;
-
-       if (copy_siginfo_from_user32(&info, uinfo))
-               return -EFAULT;
-       set_fs(KERNEL_DS);
-       ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *) &info);
-       set_fs(old_fs);
-       return ret;
-}
-
-asmlinkage long
-sys32_sigaction (int sig, struct old_sigaction32 __user *act, struct old_sigaction32 __user *oact)
-{
-       struct k_sigaction new_ka, old_ka;
-       unsigned int handler, restorer;
-       int ret;
-
-       if (act) {
-               compat_old_sigset_t mask;
-
-               ret = get_user(handler, &act->sa_handler);
-               ret |= get_user(new_ka.sa.sa_flags, &act->sa_flags);
-               ret |= get_user(restorer, &act->sa_restorer);
-               ret |= get_user(mask, &act->sa_mask);
-               if (ret)
-                       return ret;
-
-               sigact_set_handler(&new_ka, handler, restorer);
-               siginitset(&new_ka.sa.sa_mask, mask);
-       }
-
-       ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
-       if (!ret && oact) {
-               ret = put_user(IA32_SA_HANDLER(&old_ka), &oact->sa_handler);
-               ret |= put_user(old_ka.sa.sa_flags, &oact->sa_flags);
-               ret |= put_user(IA32_SA_RESTORER(&old_ka), &oact->sa_restorer);
-               ret |= put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
-       }
-
-       return ret;
-}
-
-static int
-setup_sigcontext_ia32 (struct sigcontext_ia32 __user *sc, struct _fpstate_ia32 __user *fpstate,
-                      struct pt_regs *regs, unsigned long mask)
-{
-       int  err = 0;
-       unsigned long flag;
-
-       if (!access_ok(VERIFY_WRITE, sc, sizeof(*sc)))
-               return -EFAULT;
-
-       err |= __put_user((regs->r16 >> 32) & 0xffff, (unsigned int __user *)&sc->fs);
-       err |= __put_user((regs->r16 >> 48) & 0xffff, (unsigned int __user *)&sc->gs);
-       err |= __put_user((regs->r16 >> 16) & 0xffff, (unsigned int __user *)&sc->es);
-       err |= __put_user(regs->r16 & 0xffff, (unsigned int __user *)&sc->ds);
-       err |= __put_user(regs->r15, &sc->edi);
-       err |= __put_user(regs->r14, &sc->esi);
-       err |= __put_user(regs->r13, &sc->ebp);
-       err |= __put_user(regs->r12, &sc->esp);
-       err |= __put_user(regs->r11, &sc->ebx);
-       err |= __put_user(regs->r10, &sc->edx);
-       err |= __put_user(regs->r9, &sc->ecx);
-       err |= __put_user(regs->r8, &sc->eax);
-#if 0
-       err |= __put_user(current->tss.trap_no, &sc->trapno);
-       err |= __put_user(current->tss.error_code, &sc->err);
-#endif
-       err |= __put_user(regs->cr_iip, &sc->eip);
-       err |= __put_user(regs->r17 & 0xffff, (unsigned int __user *)&sc->cs);
-       /*
-        *  `eflags' is in an ar register for this context
-        */
-       flag = ia64_getreg(_IA64_REG_AR_EFLAG);
-       err |= __put_user((unsigned int)flag, &sc->eflags);
-       err |= __put_user(regs->r12, &sc->esp_at_signal);
-       err |= __put_user((regs->r17 >> 16) & 0xffff, (unsigned int __user *)&sc->ss);
-
-       if ( save_ia32_fpstate_live(fpstate) < 0 )
-               err = -EFAULT;
-       else
-               err |= __put_user((u32)(u64)fpstate, &sc->fpstate);
-
-#if 0
-       tmp = save_i387(fpstate);
-       if (tmp < 0)
-               err = 1;
-       else
-               err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate);
-
-       /* non-iBCS2 extensions.. */
-#endif
-       err |= __put_user(mask, &sc->oldmask);
-#if 0
-       err |= __put_user(current->tss.cr2, &sc->cr2);
-#endif
-       return err;
-}
-
-static int
-restore_sigcontext_ia32 (struct pt_regs *regs, struct sigcontext_ia32 __user *sc, int *peax)
-{
-       unsigned int err = 0;
-
-       /* Always make any pending restarted system calls return -EINTR */
-       current_thread_info()->restart_block.fn = do_no_restart_syscall;
-
-       if (!access_ok(VERIFY_READ, sc, sizeof(*sc)))
-               return(-EFAULT);
-
-#define COPY(ia64x, ia32x)     err |= __get_user(regs->ia64x, &sc->ia32x)
-
-#define copyseg_gs(tmp)                (regs->r16 |= (unsigned long) (tmp) << 48)
-#define copyseg_fs(tmp)                (regs->r16 |= (unsigned long) (tmp) << 32)
-#define copyseg_cs(tmp)                (regs->r17 |= tmp)
-#define copyseg_ss(tmp)                (regs->r17 |= (unsigned long) (tmp) << 16)
-#define copyseg_es(tmp)                (regs->r16 |= (unsigned long) (tmp) << 16)
-#define copyseg_ds(tmp)                (regs->r16 |= tmp)
-
-#define COPY_SEG(seg)                                  \
-       {                                               \
-               unsigned short tmp;                     \
-               err |= __get_user(tmp, &sc->seg);       \
-               copyseg_##seg(tmp);                     \
-       }
-#define COPY_SEG_STRICT(seg)                           \
-       {                                               \
-               unsigned short tmp;                     \
-               err |= __get_user(tmp, &sc->seg);       \
-               copyseg_##seg(tmp|3);                   \
-       }
-
-       /* To make COPY_SEGs easier, we zero r16, r17 */
-       regs->r16 = 0;
-       regs->r17 = 0;
-
-       COPY_SEG(gs);
-       COPY_SEG(fs);
-       COPY_SEG(es);
-       COPY_SEG(ds);
-       COPY(r15, edi);
-       COPY(r14, esi);
-       COPY(r13, ebp);
-       COPY(r12, esp);
-       COPY(r11, ebx);
-       COPY(r10, edx);
-       COPY(r9, ecx);
-       COPY(cr_iip, eip);
-       COPY_SEG_STRICT(cs);
-       COPY_SEG_STRICT(ss);
-       ia32_load_segment_descriptors(current);
-       {
-               unsigned int tmpflags;
-               unsigned long flag;
-
-               /*
-                *  IA32 `eflags' is not part of `pt_regs', it's in an ar register which
-                *  is part of the thread context.  Fortunately, we are executing in the
-                *  IA32 process's context.
-                */
-               err |= __get_user(tmpflags, &sc->eflags);
-               flag = ia64_getreg(_IA64_REG_AR_EFLAG);
-               flag &= ~0x40DD5;
-               flag |= (tmpflags & 0x40DD5);
-               ia64_setreg(_IA64_REG_AR_EFLAG, flag);
-
-               regs->r1 = -1;  /* disable syscall checks, r1 is orig_eax */
-       }
-
-       {
-               struct _fpstate_ia32 __user *buf = NULL;
-               u32    fpstate_ptr;
-               err |= get_user(fpstate_ptr, &(sc->fpstate));
-               buf = compat_ptr(fpstate_ptr);
-               if (buf) {
-                       err |= restore_ia32_fpstate_live(buf);
-               }
-       }
-
-#if 0
-       {
-               struct _fpstate * buf;
-               err |= __get_user(buf, &sc->fpstate);
-               if (buf) {
-                       if (!access_ok(VERIFY_READ, buf, sizeof(*buf)))
-                               goto badframe;
-                       err |= restore_i387(buf);
-               }
-       }
-#endif
-
-       err |= __get_user(*peax, &sc->eax);
-       return err;
-
-#if 0
-  badframe:
-       return 1;
-#endif
-}
-
-/*
- * Determine which stack to use..
- */
-static inline void __user *
-get_sigframe (struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
-{
-       unsigned long esp;
-
-       /* Default to using normal stack (truncate off sign-extension of bit 31: */
-       esp = (unsigned int) regs->r12;
-
-       /* This is the X/Open sanctioned signal stack switching.  */
-       if (ka->sa.sa_flags & SA_ONSTACK) {
-               int onstack = sas_ss_flags(esp);
-
-               if (onstack == 0)
-                       esp = current->sas_ss_sp + current->sas_ss_size;
-               else if (onstack == SS_ONSTACK) {
-                       /*
-                        * If we are on the alternate signal stack and would
-                        * overflow it, don't. Return an always-bogus address
-                        * instead so we will die with SIGSEGV.
-                        */
-                       if (!likely(on_sig_stack(esp - frame_size)))
-                               return (void __user *) -1L;
-               }
-       }
-       /* Legacy stack switching not supported */
-
-       esp -= frame_size;
-       /* Align the stack pointer according to the i386 ABI,
-        * i.e. so that on function entry ((sp + 4) & 15) == 0. */
-       esp = ((esp + 4) & -16ul) - 4;
-       return (void __user *) esp;
-}
-
-static int
-setup_frame_ia32 (int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs)
-{
-       struct exec_domain *ed = current_thread_info()->exec_domain;
-       struct sigframe_ia32 __user *frame;
-       int err = 0;
-
-       frame = get_sigframe(ka, regs, sizeof(*frame));
-
-       if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-               goto give_sigsegv;
-
-       err |= __put_user((ed && ed->signal_invmap && sig < 32
-                          ? (int)(ed->signal_invmap[sig]) : sig), &frame->sig);
-
-       err |= setup_sigcontext_ia32(&frame->sc, &frame->fpstate, regs, set->sig[0]);
-
-       if (_COMPAT_NSIG_WORDS > 1)
-               err |= __copy_to_user(frame->extramask, (char *) &set->sig + 4,
-                                     sizeof(frame->extramask));
-
-       /* Set up to return from userspace.  If provided, use a stub
-          already in userspace.  */
-       if (ka->sa.sa_flags & SA_RESTORER) {
-               unsigned int restorer = IA32_SA_RESTORER(ka);
-               err |= __put_user(restorer, &frame->pretcode);
-       } else {
-               /* Pointing to restorer in ia32 gate page */
-               err |= __put_user(IA32_GATE_OFFSET, &frame->pretcode);
-       }
-
-       /* This is popl %eax ; movl $,%eax ; int $0x80
-        * and there for historical reasons only.
-        * See arch/i386/kernel/signal.c
-        */
-
-       err |= __put_user(0xb858, (short __user *)(frame->retcode+0));
-       err |= __put_user(__IA32_NR_sigreturn, (int __user *)(frame->retcode+2));
-       err |= __put_user(0x80cd, (short __user *)(frame->retcode+6));
-
-       if (err)
-               goto give_sigsegv;
-
-       /* Set up registers for signal handler */
-       regs->r12 = (unsigned long) frame;
-       regs->cr_iip = IA32_SA_HANDLER(ka);
-
-       set_fs(USER_DS);
-
-#if 0
-       regs->eflags &= ~TF_MASK;
-#endif
-
-#if 0
-       printk("SIG deliver (%s:%d): sig=%d sp=%p pc=%lx ra=%x\n",
-               current->comm, current->pid, sig, (void *) frame, regs->cr_iip, frame->pretcode);
-#endif
-
-       return 1;
-
-  give_sigsegv:
-       force_sigsegv(sig, current);
-       return 0;
-}
-
-static int
-setup_rt_frame_ia32 (int sig, struct k_sigaction *ka, siginfo_t *info,
-                    sigset_t *set, struct pt_regs * regs)
-{
-       struct exec_domain *ed = current_thread_info()->exec_domain;
-       compat_uptr_t pinfo, puc;
-       struct rt_sigframe_ia32 __user *frame;
-       int err = 0;
-
-       frame = get_sigframe(ka, regs, sizeof(*frame));
-
-       if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-               goto give_sigsegv;
-
-       err |= __put_user((ed && ed->signal_invmap
-                          && sig < 32 ? ed->signal_invmap[sig] : sig), &frame->sig);
-
-       pinfo = (long __user) &frame->info;
-       puc = (long __user) &frame->uc;
-       err |= __put_user(pinfo, &frame->pinfo);
-       err |= __put_user(puc, &frame->puc);
-       err |= copy_siginfo_to_user32(&frame->info, info);
-
-       /* Create the ucontext.  */
-       err |= __put_user(0, &frame->uc.uc_flags);
-       err |= __put_user(0, &frame->uc.uc_link);
-       err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
-       err |= __put_user(sas_ss_flags(regs->r12), &frame->uc.uc_stack.ss_flags);
-       err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
-       err |= setup_sigcontext_ia32(&frame->uc.uc_mcontext, &frame->fpstate, regs, set->sig[0]);
-       err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
-       if (err)
-               goto give_sigsegv;
-
-       /* Set up to return from userspace.  If provided, use a stub
-          already in userspace.  */
-       if (ka->sa.sa_flags & SA_RESTORER) {
-               unsigned int restorer = IA32_SA_RESTORER(ka);
-               err |= __put_user(restorer, &frame->pretcode);
-       } else {
-               /* Pointing to rt_restorer in ia32 gate page */
-               err |= __put_user(IA32_GATE_OFFSET + 8, &frame->pretcode);
-       }
-
-       /* This is movl $,%eax ; int $0x80
-        * and there for historical reasons only.
-        * See arch/i386/kernel/signal.c
-        */
-
-       err |= __put_user(0xb8, (char __user *)(frame->retcode+0));
-       err |= __put_user(__IA32_NR_rt_sigreturn, (int __user *)(frame->retcode+1));
-       err |= __put_user(0x80cd, (short __user *)(frame->retcode+5));
-
-       if (err)
-               goto give_sigsegv;
-
-       /* Set up registers for signal handler */
-       regs->r12 = (unsigned long) frame;
-       regs->cr_iip = IA32_SA_HANDLER(ka);
-
-       set_fs(USER_DS);
-
-#if 0
-       regs->eflags &= ~TF_MASK;
-#endif
-
-#if 0
-       printk("SIG deliver (%s:%d): sp=%p pc=%lx ra=%x\n",
-               current->comm, current->pid, (void *) frame, regs->cr_iip, frame->pretcode);
-#endif
-
-       return 1;
-
-give_sigsegv:
-       force_sigsegv(sig, current);
-       return 0;
-}
-
-int
-ia32_setup_frame1 (int sig, struct k_sigaction *ka, siginfo_t *info,
-                  sigset_t *set, struct pt_regs *regs)
-{
-       /* Set up the stack frame */
-       if (ka->sa.sa_flags & SA_SIGINFO)
-               return setup_rt_frame_ia32(sig, ka, info, set, regs);
-       else
-               return setup_frame_ia32(sig, ka, set, regs);
-}
-
-asmlinkage long
-sys32_sigreturn (int arg0, int arg1, int arg2, int arg3, int arg4, int arg5,
-                int arg6, int arg7, struct pt_regs regs)
-{
-       unsigned long esp = (unsigned int) regs.r12;
-       struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(esp - 8);
-       sigset_t set;
-       int eax;
-
-       if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
-               goto badframe;
-
-       if (__get_user(set.sig[0], &frame->sc.oldmask)
-           || (_COMPAT_NSIG_WORDS > 1 && __copy_from_user((char *) &set.sig + 4, &frame->extramask,
-                                                        sizeof(frame->extramask))))
-               goto badframe;
-
-       sigdelsetmask(&set, ~_BLOCKABLE);
-       spin_lock_irq(&current->sighand->siglock);
-       current->blocked = set;
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
-
-       if (restore_sigcontext_ia32(&regs, &frame->sc, &eax))
-               goto badframe;
-       return eax;
-
-  badframe:
-       force_sig(SIGSEGV, current);
-       return 0;
-}
-
-asmlinkage long
-sys32_rt_sigreturn (int arg0, int arg1, int arg2, int arg3, int arg4,
-                   int arg5, int arg6, int arg7, struct pt_regs regs)
-{
-       unsigned long esp = (unsigned int) regs.r12;
-       struct rt_sigframe_ia32 __user *frame = (struct rt_sigframe_ia32 __user *)(esp - 4);
-       sigset_t set;
-       int eax;
-
-       if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
-               goto badframe;
-       if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
-               goto badframe;
-
-       sigdelsetmask(&set, ~_BLOCKABLE);
-       spin_lock_irq(&current->sighand->siglock);
-       current->blocked =  set;
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
-
-       if (restore_sigcontext_ia32(&regs, &frame->uc.uc_mcontext, &eax))
-               goto badframe;
-
-       /* It is more difficult to avoid calling this function than to
-          call it and ignore errors.  */
-       do_sigaltstack((stack_t __user *) &frame->uc.uc_stack, NULL, esp);
-
-       return eax;
-
-  badframe:
-       force_sig(SIGSEGV, current);
-       return 0;
-}
diff --git a/arch/ia64/ia32/ia32_support.c b/arch/ia64/ia32/ia32_support.c
deleted file mode 100644 (file)
index a6965dd..0000000
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * IA32 helper functions
- *
- * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com>
- * Copyright (C) 2000 Asit K. Mallick <asit.k.mallick@intel.com>
- * Copyright (C) 2001-2002 Hewlett-Packard Co
- *     David Mosberger-Tang <davidm@hpl.hp.com>
- *
- * 06/16/00    A. Mallick      added csd/ssd/tssd for ia32 thread context
- * 02/19/01    D. Mosberger    dropped tssd; it's not needed
- * 09/14/01    D. Mosberger    fixed memory management for gdt/tss page
- * 09/29/01    D. Mosberger    added ia32_load_segment_descriptors()
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-
-#include <asm/intrinsics.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/processor.h>
-#include <asm/uaccess.h>
-
-#include "ia32priv.h"
-
-extern int die_if_kernel (char *str, struct pt_regs *regs, long err);
-
-struct page *ia32_shared_page[NR_CPUS];
-unsigned long *ia32_boot_gdt;
-unsigned long *cpu_gdt_table[NR_CPUS];
-struct page *ia32_gate_page;
-
-static unsigned long
-load_desc (u16 selector)
-{
-       unsigned long *table, limit, index;
-
-       if (!selector)
-               return 0;
-       if (selector & IA32_SEGSEL_TI) {
-               table = (unsigned long *) IA32_LDT_OFFSET;
-               limit = IA32_LDT_ENTRIES;
-       } else {
-               table = cpu_gdt_table[smp_processor_id()];
-               limit = IA32_PAGE_SIZE / sizeof(ia32_boot_gdt[0]);
-       }
-       index = selector >> IA32_SEGSEL_INDEX_SHIFT;
-       if (index >= limit)
-               return 0;
-       return IA32_SEG_UNSCRAMBLE(table[index]);
-}
-
-void
-ia32_load_segment_descriptors (struct task_struct *task)
-{
-       struct pt_regs *regs = task_pt_regs(task);
-
-       /* Setup the segment descriptors */
-       regs->r24 = load_desc(regs->r16 >> 16);         /* ESD */
-       regs->r27 = load_desc(regs->r16 >>  0);         /* DSD */
-       regs->r28 = load_desc(regs->r16 >> 32);         /* FSD */
-       regs->r29 = load_desc(regs->r16 >> 48);         /* GSD */
-       regs->ar_csd = load_desc(regs->r17 >>  0);      /* CSD */
-       regs->ar_ssd = load_desc(regs->r17 >> 16);      /* SSD */
-}
-
-int
-ia32_clone_tls (struct task_struct *child, struct pt_regs *childregs)
-{
-       struct desc_struct *desc;
-       struct ia32_user_desc info;
-       int idx;
-
-       if (copy_from_user(&info, (void __user *)(childregs->r14 & 0xffffffff), sizeof(info)))
-               return -EFAULT;
-       if (LDT_empty(&info))
-               return -EINVAL;
-
-       idx = info.entry_number;
-       if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
-               return -EINVAL;
-
-       desc = child->thread.tls_array + idx - GDT_ENTRY_TLS_MIN;
-       desc->a = LDT_entry_a(&info);
-       desc->b = LDT_entry_b(&info);
-
-       /* XXX: can this be done in a cleaner way ? */
-       load_TLS(&child->thread, smp_processor_id());
-       ia32_load_segment_descriptors(child);
-       load_TLS(&current->thread, smp_processor_id());
-
-       return 0;
-}
-
-void
-ia32_save_state (struct task_struct *t)
-{
-       t->thread.eflag = ia64_getreg(_IA64_REG_AR_EFLAG);
-       t->thread.fsr   = ia64_getreg(_IA64_REG_AR_FSR);
-       t->thread.fcr   = ia64_getreg(_IA64_REG_AR_FCR);
-       t->thread.fir   = ia64_getreg(_IA64_REG_AR_FIR);
-       t->thread.fdr   = ia64_getreg(_IA64_REG_AR_FDR);
-       ia64_set_kr(IA64_KR_IO_BASE, t->thread.old_iob);
-       ia64_set_kr(IA64_KR_TSSD, t->thread.old_k1);
-}
-
-void
-ia32_load_state (struct task_struct *t)
-{
-       unsigned long eflag, fsr, fcr, fir, fdr, tssd;
-       struct pt_regs *regs = task_pt_regs(t);
-
-       eflag = t->thread.eflag;
-       fsr = t->thread.fsr;
-       fcr = t->thread.fcr;
-       fir = t->thread.fir;
-       fdr = t->thread.fdr;
-       tssd = load_desc(_TSS);                                 /* TSSD */
-
-       ia64_setreg(_IA64_REG_AR_EFLAG, eflag);
-       ia64_setreg(_IA64_REG_AR_FSR, fsr);
-       ia64_setreg(_IA64_REG_AR_FCR, fcr);
-       ia64_setreg(_IA64_REG_AR_FIR, fir);
-       ia64_setreg(_IA64_REG_AR_FDR, fdr);
-       current->thread.old_iob = ia64_get_kr(IA64_KR_IO_BASE);
-       current->thread.old_k1 = ia64_get_kr(IA64_KR_TSSD);
-       ia64_set_kr(IA64_KR_IO_BASE, IA32_IOBASE);
-       ia64_set_kr(IA64_KR_TSSD, tssd);
-
-       regs->r17 = (_TSS << 48) | (_LDT << 32) | (__u32) regs->r17;
-       regs->r30 = load_desc(_LDT);                            /* LDTD */
-       load_TLS(&t->thread, smp_processor_id());
-}
-
-/*
- * Setup IA32 GDT and TSS
- */
-void
-ia32_gdt_init (void)
-{
-       int cpu = smp_processor_id();
-
-       ia32_shared_page[cpu] = alloc_page(GFP_KERNEL);
-       if (!ia32_shared_page[cpu])
-               panic("failed to allocate ia32_shared_page[%d]\n", cpu);
-
-       cpu_gdt_table[cpu] = page_address(ia32_shared_page[cpu]);
-
-       /* Copy from the boot cpu's GDT */
-       memcpy(cpu_gdt_table[cpu], ia32_boot_gdt, PAGE_SIZE);
-}
-
-
-/*
- * Setup IA32 GDT and TSS
- */
-static void
-ia32_boot_gdt_init (void)
-{
-       unsigned long ldt_size;
-
-       ia32_shared_page[0] = alloc_page(GFP_KERNEL);
-       if (!ia32_shared_page[0])
-               panic("failed to allocate ia32_shared_page[0]\n");
-
-       ia32_boot_gdt = page_address(ia32_shared_page[0]);
-       cpu_gdt_table[0] = ia32_boot_gdt;
-
-       /* CS descriptor in IA-32 (scrambled) format */
-       ia32_boot_gdt[__USER_CS >> 3]
-               = IA32_SEG_DESCRIPTOR(0, (IA32_GATE_END-1) >> IA32_PAGE_SHIFT,
-                                     0xb, 1, 3, 1, 1, 1, 1);
-
-       /* DS descriptor in IA-32 (scrambled) format */
-       ia32_boot_gdt[__USER_DS >> 3]
-               = IA32_SEG_DESCRIPTOR(0, (IA32_GATE_END-1) >> IA32_PAGE_SHIFT,
-                                     0x3, 1, 3, 1, 1, 1, 1);
-
-       ldt_size = PAGE_ALIGN(IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE);
-       ia32_boot_gdt[TSS_ENTRY] = IA32_SEG_DESCRIPTOR(IA32_TSS_OFFSET, 235,
-                                                      0xb, 0, 3, 1, 1, 1, 0);
-       ia32_boot_gdt[LDT_ENTRY] = IA32_SEG_DESCRIPTOR(IA32_LDT_OFFSET, ldt_size - 1,
-                                                      0x2, 0, 3, 1, 1, 1, 0);
-}
-
-static void
-ia32_gate_page_init(void)
-{
-       unsigned long *sr;
-
-       ia32_gate_page = alloc_page(GFP_KERNEL);
-       sr = page_address(ia32_gate_page);
-       /* This is popl %eax ; movl $,%eax ; int $0x80 */
-       *sr++ = 0xb858 | (__IA32_NR_sigreturn << 16) | (0x80cdUL << 48);
-
-       /* This is movl $,%eax ; int $0x80 */
-       *sr = 0xb8 | (__IA32_NR_rt_sigreturn << 8) | (0x80cdUL << 40);
-}
-
-void
-ia32_mem_init(void)
-{
-       ia32_boot_gdt_init();
-       ia32_gate_page_init();
-}
-
-/*
- * Handle bad IA32 interrupt via syscall
- */
-void
-ia32_bad_interrupt (unsigned long int_num, struct pt_regs *regs)
-{
-       siginfo_t siginfo;
-
-       if (die_if_kernel("Bad IA-32 interrupt", regs, int_num))
-               return;
-
-       siginfo.si_signo = SIGTRAP;
-       siginfo.si_errno = int_num;     /* XXX is it OK to abuse si_errno like this? */
-       siginfo.si_flags = 0;
-       siginfo.si_isr = 0;
-       siginfo.si_addr = NULL;
-       siginfo.si_imm = 0;
-       siginfo.si_code = TRAP_BRKPT;
-       force_sig_info(SIGTRAP, &siginfo, current);
-}
-
-void
-ia32_cpu_init (void)
-{
-       /* initialize global ia32 state - CR0 and CR4 */
-       ia64_setreg(_IA64_REG_AR_CFLAG, (((ulong) IA32_CR4 << 32) | IA32_CR0));
-}
-
-static int __init
-ia32_init (void)
-{
-#if PAGE_SHIFT > IA32_PAGE_SHIFT
-       {
-               extern struct kmem_cache *ia64_partial_page_cachep;
-
-               ia64_partial_page_cachep = kmem_cache_create("ia64_partial_page_cache",
-                                       sizeof(struct ia64_partial_page),
-                                       0, SLAB_PANIC, NULL);
-       }
-#endif
-       return 0;
-}
-
-__initcall(ia32_init);
diff --git a/arch/ia64/ia32/ia32_traps.c b/arch/ia64/ia32/ia32_traps.c
deleted file mode 100644 (file)
index e486042..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * IA-32 exception handlers
- *
- * Copyright (C) 2000 Asit K. Mallick <asit.k.mallick@intel.com>
- * Copyright (C) 2001-2002 Hewlett-Packard Co
- *     David Mosberger-Tang <davidm@hpl.hp.com>
- *
- * 06/16/00    A. Mallick      added siginfo for most cases (close to IA32)
- * 09/29/00    D. Mosberger    added ia32_intercept()
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-
-#include "ia32priv.h"
-
-#include <asm/intrinsics.h>
-#include <asm/ptrace.h>
-
-int
-ia32_intercept (struct pt_regs *regs, unsigned long isr)
-{
-       switch ((isr >> 16) & 0xff) {
-             case 0:   /* Instruction intercept fault */
-             case 4:   /* Locked Data reference fault */
-             case 1:   /* Gate intercept trap */
-               return -1;
-
-             case 2:   /* System flag trap */
-               if (((isr >> 14) & 0x3) >= 2) {
-                       /* MOV SS, POP SS instructions */
-                       ia64_psr(regs)->id = 1;
-                       return 0;
-               } else
-                       return -1;
-       }
-       return -1;
-}
-
-int
-ia32_exception (struct pt_regs *regs, unsigned long isr)
-{
-       struct siginfo siginfo;
-
-       /* initialize these fields to avoid leaking kernel bits to user space: */
-       siginfo.si_errno = 0;
-       siginfo.si_flags = 0;
-       siginfo.si_isr = 0;
-       siginfo.si_imm = 0;
-       switch ((isr >> 16) & 0xff) {
-             case 1:
-             case 2:
-               siginfo.si_signo = SIGTRAP;
-               if (isr == 0)
-                       siginfo.si_code = TRAP_TRACE;
-               else if (isr & 0x4)
-                       siginfo.si_code = TRAP_BRANCH;
-               else
-                       siginfo.si_code = TRAP_BRKPT;
-               break;
-
-             case 3:
-               siginfo.si_signo = SIGTRAP;
-               siginfo.si_code = TRAP_BRKPT;
-               break;
-
-             case 0:   /* Divide fault */
-               siginfo.si_signo = SIGFPE;
-               siginfo.si_code = FPE_INTDIV;
-               break;
-
-             case 4:   /* Overflow */
-             case 5:   /* Bounds fault */
-               siginfo.si_signo = SIGFPE;
-               siginfo.si_code = 0;
-               break;
-
-             case 6:   /* Invalid Op-code */
-               siginfo.si_signo = SIGILL;
-               siginfo.si_code = ILL_ILLOPN;
-               break;
-
-             case 7:   /* FP DNA */
-             case 8:   /* Double Fault */
-             case 9:   /* Invalid TSS */
-             case 11:  /* Segment not present */
-             case 12:  /* Stack fault */
-             case 13:  /* General Protection Fault */
-               siginfo.si_signo = SIGSEGV;
-               siginfo.si_code = 0;
-               break;
-
-             case 16:  /* Pending FP error */
-               {
-                       unsigned long fsr, fcr;
-
-                       fsr = ia64_getreg(_IA64_REG_AR_FSR);
-                       fcr = ia64_getreg(_IA64_REG_AR_FCR);
-
-                       siginfo.si_signo = SIGFPE;
-                       /*
-                        * (~cwd & swd) will mask out exceptions that are not set to unmasked
-                        * status.  0x3f is the exception bits in these regs, 0x200 is the
-                        * C1 reg you need in case of a stack fault, 0x040 is the stack
-                        * fault bit.  We should only be taking one exception at a time,
-                        * so if this combination doesn't produce any single exception,
-                        * then we have a bad program that isn't synchronizing its FPU usage
-                        * and it will suffer the consequences since we won't be able to
-                        * fully reproduce the context of the exception
-                        */
-                       siginfo.si_isr = isr;
-                       siginfo.si_flags = __ISR_VALID;
-                       switch(((~fcr) & (fsr & 0x3f)) | (fsr & 0x240)) {
-                               case 0x000:
-                               default:
-                                       siginfo.si_code = 0;
-                                       break;
-                               case 0x001: /* Invalid Op */
-                               case 0x040: /* Stack Fault */
-                               case 0x240: /* Stack Fault | Direction */
-                                       siginfo.si_code = FPE_FLTINV;
-                                       break;
-                               case 0x002: /* Denormalize */
-                               case 0x010: /* Underflow */
-                                       siginfo.si_code = FPE_FLTUND;
-                                       break;
-                               case 0x004: /* Zero Divide */
-                                       siginfo.si_code = FPE_FLTDIV;
-                                       break;
-                               case 0x008: /* Overflow */
-                                       siginfo.si_code = FPE_FLTOVF;
-                                       break;
-                               case 0x020: /* Precision */
-                                       siginfo.si_code = FPE_FLTRES;
-                                       break;
-                       }
-
-                       break;
-               }
-
-             case 17:  /* Alignment check */
-               siginfo.si_signo = SIGSEGV;
-               siginfo.si_code = BUS_ADRALN;
-               break;
-
-             case 19:  /* SSE Numeric error */
-               siginfo.si_signo = SIGFPE;
-               siginfo.si_code = 0;
-               break;
-
-             default:
-               return -1;
-       }
-       force_sig_info(siginfo.si_signo, &siginfo, current);
-       return 0;
-}
diff --git a/arch/ia64/ia32/ia32priv.h b/arch/ia64/ia32/ia32priv.h
deleted file mode 100644 (file)
index 0f15349..0000000
+++ /dev/null
@@ -1,532 +0,0 @@
-#ifndef _ASM_IA64_IA32_PRIV_H
-#define _ASM_IA64_IA32_PRIV_H
-
-
-#include <asm/ia32.h>
-
-#ifdef CONFIG_IA32_SUPPORT
-
-#include <linux/binfmts.h>
-#include <linux/compat.h>
-#include <linux/rbtree.h>
-
-#include <asm/processor.h>
-
-/*
- * 32 bit structures for IA32 support.
- */
-
-#define IA32_PAGE_SIZE         (1UL << IA32_PAGE_SHIFT)
-#define IA32_PAGE_MASK         (~(IA32_PAGE_SIZE - 1))
-#define IA32_PAGE_ALIGN(addr)  (((addr) + IA32_PAGE_SIZE - 1) & IA32_PAGE_MASK)
-#define IA32_CLOCKS_PER_SEC    100     /* Cast in stone for IA32 Linux */
-
-/*
- * partially mapped pages provide precise accounting of which 4k sub pages
- * are mapped and which ones are not, thereby improving IA-32 compatibility.
- */
-struct ia64_partial_page {
-       struct ia64_partial_page *next; /* linked list, sorted by address */
-       struct rb_node          pp_rb;
-       /* 64K is the largest "normal" page supported by ia64 ABI. So 4K*64
-        * should suffice.*/
-       unsigned long           bitmap;
-       unsigned int            base;
-};
-
-struct ia64_partial_page_list {
-       struct ia64_partial_page *pp_head; /* list head, points to the lowest
-                                          * addressed partial page */
-       struct rb_root          ppl_rb;
-       struct ia64_partial_page *pp_hint; /* pp_hint->next is the last
-                                          * accessed partial page */
-       atomic_t                pp_count; /* reference count */
-};
-
-#if PAGE_SHIFT > IA32_PAGE_SHIFT
-struct ia64_partial_page_list* ia32_init_pp_list (void);
-#else
-# define ia32_init_pp_list()   0
-#endif
-
-/* sigcontext.h */
-/*
- * As documented in the iBCS2 standard..
- *
- * The first part of "struct _fpstate" is just the
- * normal i387 hardware setup, the extra "status"
- * word is used to save the coprocessor status word
- * before entering the handler.
- */
-struct _fpreg_ia32 {
-       unsigned short significand[4];
-       unsigned short exponent;
-};
-
-struct _fpxreg_ia32 {
-        unsigned short significand[4];
-        unsigned short exponent;
-        unsigned short padding[3];
-};
-
-struct _xmmreg_ia32 {
-        unsigned int element[4];
-};
-
-
-struct _fpstate_ia32 {
-       unsigned int    cw,
-                      sw,
-                      tag,
-                      ipoff,
-                      cssel,
-                      dataoff,
-                      datasel;
-       struct _fpreg_ia32      _st[8];
-       unsigned short  status;
-       unsigned short  magic;          /* 0xffff = regular FPU data only */
-
-       /* FXSR FPU environment */
-       unsigned int         _fxsr_env[6];   /* FXSR FPU env is ignored */
-       unsigned int         mxcsr;
-       unsigned int         reserved;
-       struct _fpxreg_ia32  _fxsr_st[8];    /* FXSR FPU reg data is ignored */
-       struct _xmmreg_ia32  _xmm[8];
-       unsigned int         padding[56];
-};
-
-struct sigcontext_ia32 {
-       unsigned short gs, __gsh;
-       unsigned short fs, __fsh;
-       unsigned short es, __esh;
-       unsigned short ds, __dsh;
-       unsigned int edi;
-       unsigned int esi;
-       unsigned int ebp;
-       unsigned int esp;
-       unsigned int ebx;
-       unsigned int edx;
-       unsigned int ecx;
-       unsigned int eax;
-       unsigned int trapno;
-       unsigned int err;
-       unsigned int eip;
-       unsigned short cs, __csh;
-       unsigned int eflags;
-       unsigned int esp_at_signal;
-       unsigned short ss, __ssh;
-       unsigned int fpstate;           /* really (struct _fpstate_ia32 *) */
-       unsigned int oldmask;
-       unsigned int cr2;
-};
-
-/* user.h */
-/*
- * IA32 (Pentium III/4) FXSR, SSE support
- *
- * Provide support for the GDB 5.0+ PTRACE_{GET|SET}FPXREGS requests for
- * interacting with the FXSR-format floating point environment.  Floating
- * point data can be accessed in the regular format in the usual manner,
- * and both the standard and SIMD floating point data can be accessed via
- * the new ptrace requests.  In either case, changes to the FPU environment
- * will be reflected in the task's state as expected.
- */
-struct ia32_user_i387_struct {
-       int     cwd;
-       int     swd;
-       int     twd;
-       int     fip;
-       int     fcs;
-       int     foo;
-       int     fos;
-       /* 8*10 bytes for each FP-reg = 80 bytes */
-       struct _fpreg_ia32      st_space[8];
-};
-
-struct ia32_user_fxsr_struct {
-       unsigned short  cwd;
-       unsigned short  swd;
-       unsigned short  twd;
-       unsigned short  fop;
-       int     fip;
-       int     fcs;
-       int     foo;
-       int     fos;
-       int     mxcsr;
-       int     reserved;
-       int     st_space[32];   /* 8*16 bytes for each FP-reg = 128 bytes */
-       int     xmm_space[32];  /* 8*16 bytes for each XMM-reg = 128 bytes */
-       int     padding[56];
-};
-
-/* signal.h */
-#define IA32_SET_SA_HANDLER(ka,handler,restorer)                               \
-                               ((ka)->sa.sa_handler = (__sighandler_t)         \
-                                       (((unsigned long)(restorer) << 32)      \
-                                        | ((handler) & 0xffffffff)))
-#define IA32_SA_HANDLER(ka)    ((unsigned long) (ka)->sa.sa_handler & 0xffffffff)
-#define IA32_SA_RESTORER(ka)   ((unsigned long) (ka)->sa.sa_handler >> 32)
-
-#define __IA32_NR_sigreturn 119
-#define __IA32_NR_rt_sigreturn 173
-
-struct sigaction32 {
-       unsigned int sa_handler;                /* Really a pointer, but need to deal with 32 bits */
-       unsigned int sa_flags;
-       unsigned int sa_restorer;       /* Another 32 bit pointer */
-       compat_sigset_t sa_mask;                /* A 32 bit mask */
-};
-
-struct old_sigaction32 {
-       unsigned int  sa_handler;       /* Really a pointer, but need to deal
-                                            with 32 bits */
-       compat_old_sigset_t sa_mask;            /* A 32 bit mask */
-       unsigned int sa_flags;
-       unsigned int sa_restorer;       /* Another 32 bit pointer */
-};
-
-typedef struct sigaltstack_ia32 {
-       unsigned int    ss_sp;
-       int             ss_flags;
-       unsigned int    ss_size;
-} stack_ia32_t;
-
-struct ucontext_ia32 {
-       unsigned int      uc_flags;
-       unsigned int      uc_link;
-       stack_ia32_t      uc_stack;
-       struct sigcontext_ia32 uc_mcontext;
-       sigset_t          uc_sigmask;   /* mask last for extensibility */
-};
-
-struct stat64 {
-       unsigned long long      st_dev;
-       unsigned char   __pad0[4];
-       unsigned int    __st_ino;
-       unsigned int    st_mode;
-       unsigned int    st_nlink;
-       unsigned int    st_uid;
-       unsigned int    st_gid;
-       unsigned long long      st_rdev;
-       unsigned char   __pad3[4];
-       unsigned int    st_size_lo;
-       unsigned int    st_size_hi;
-       unsigned int    st_blksize;
-       unsigned int    st_blocks;      /* Number 512-byte blocks allocated. */
-       unsigned int    __pad4;         /* future possible st_blocks high bits */
-       unsigned int    st_atime;
-       unsigned int    st_atime_nsec;
-       unsigned int    st_mtime;
-       unsigned int    st_mtime_nsec;
-       unsigned int    st_ctime;
-       unsigned int    st_ctime_nsec;
-       unsigned int    st_ino_lo;
-       unsigned int    st_ino_hi;
-};
-
-typedef struct compat_siginfo {
-       int si_signo;
-       int si_errno;
-       int si_code;
-
-       union {
-               int _pad[((128/sizeof(int)) - 3)];
-
-               /* kill() */
-               struct {
-                       unsigned int _pid;      /* sender's pid */
-                       unsigned int _uid;      /* sender's uid */
-               } _kill;
-
-               /* POSIX.1b timers */
-               struct {
-                       compat_timer_t _tid;            /* timer id */
-                       int _overrun;           /* overrun count */
-                       char _pad[sizeof(unsigned int) - sizeof(int)];
-                       compat_sigval_t _sigval;        /* same as below */
-                       int _sys_private;       /* not to be passed to user */
-               } _timer;
-
-               /* POSIX.1b signals */
-               struct {
-                       unsigned int _pid;      /* sender's pid */
-                       unsigned int _uid;      /* sender's uid */
-                       compat_sigval_t _sigval;
-               } _rt;
-
-               /* SIGCHLD */
-               struct {
-                       unsigned int _pid;      /* which child */
-                       unsigned int _uid;      /* sender's uid */
-                       int _status;            /* exit code */
-                       compat_clock_t _utime;
-                       compat_clock_t _stime;
-               } _sigchld;
-
-               /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
-               struct {
-                       unsigned int _addr;     /* faulting insn/memory ref. */
-               } _sigfault;
-
-               /* SIGPOLL */
-               struct {
-                       int _band;      /* POLL_IN, POLL_OUT, POLL_MSG */
-                       int _fd;
-               } _sigpoll;
-       } _sifields;
-} compat_siginfo_t;
-
-/*
- * IA-32 ELF specific definitions for IA-64.
- */
-
-#define _ASM_IA64_ELF_H                /* Don't include elf.h */
-
-#include <linux/sched.h>
-
-/*
- * This is used to ensure we don't load something for the wrong architecture.
- */
-#define elf_check_arch(x) ((x)->e_machine == EM_386)
-
-/*
- * These are used to set parameters in the core dumps.
- */
-#define ELF_CLASS      ELFCLASS32
-#define ELF_DATA       ELFDATA2LSB
-#define ELF_ARCH       EM_386
-
-#define IA32_STACK_TOP         IA32_PAGE_OFFSET
-#define IA32_GATE_OFFSET       IA32_PAGE_OFFSET
-#define IA32_GATE_END          IA32_PAGE_OFFSET + PAGE_SIZE
-
-/*
- * The system segments (GDT, TSS, LDT) have to be mapped below 4GB so the IA-32 engine can
- * access them.
- */
-#define IA32_GDT_OFFSET                (IA32_PAGE_OFFSET + PAGE_SIZE)
-#define IA32_TSS_OFFSET                (IA32_PAGE_OFFSET + 2*PAGE_SIZE)
-#define IA32_LDT_OFFSET                (IA32_PAGE_OFFSET + 3*PAGE_SIZE)
-
-#define ELF_EXEC_PAGESIZE      IA32_PAGE_SIZE
-
-/*
- * This is the location that an ET_DYN program is loaded if exec'ed.
- * Typical use of this is to invoke "./ld.so someprog" to test out a
- * new version of the loader.  We need to make sure that it is out of
- * the way of the program that it will "exec", and that there is
- * sufficient room for the brk.
- */
-#define ELF_ET_DYN_BASE                (IA32_PAGE_OFFSET/3 + 0x1000000)
-
-void ia64_elf32_init(struct pt_regs *regs);
-#define ELF_PLAT_INIT(_r, load_addr)   ia64_elf32_init(_r)
-
-/* This macro yields a bitmask that programs can use to figure out
-   what instruction set this CPU supports.  */
-#define ELF_HWCAP      0
-
-/* This macro yields a string that ld.so will use to load
-   implementation specific libraries for optimization.  Not terribly
-   relevant until we have real hardware to play with... */
-#define ELF_PLATFORM   NULL
-
-#ifdef __KERNEL__
-# define SET_PERSONALITY(EX)                           \
-       (current->personality = PER_LINUX)
-#endif
-
-#define IA32_EFLAG     0x200
-
-/*
- * IA-32 ELF specific definitions for IA-64.
- */
-
-#define __USER_CS      0x23
-#define __USER_DS      0x2B
-
-/*
- * The per-cpu GDT has 32 entries: see <asm-i386/segment.h>
- */
-#define GDT_ENTRIES 32
-
-#define GDT_SIZE       (GDT_ENTRIES * 8)
-
-#define TSS_ENTRY 14
-#define LDT_ENTRY      (TSS_ENTRY + 1)
-
-#define IA32_SEGSEL_RPL                (0x3 << 0)
-#define IA32_SEGSEL_TI         (0x1 << 2)
-#define IA32_SEGSEL_INDEX_SHIFT        3
-
-#define _TSS                   ((unsigned long) TSS_ENTRY << IA32_SEGSEL_INDEX_SHIFT)
-#define _LDT                   ((unsigned long) LDT_ENTRY << IA32_SEGSEL_INDEX_SHIFT)
-
-#define IA32_SEG_BASE          16
-#define IA32_SEG_TYPE          40
-#define IA32_SEG_SYS           44
-#define IA32_SEG_DPL           45
-#define IA32_SEG_P             47
-#define IA32_SEG_HIGH_LIMIT    48
-#define IA32_SEG_AVL           52
-#define IA32_SEG_DB            54
-#define IA32_SEG_G             55
-#define IA32_SEG_HIGH_BASE     56
-
-#define IA32_SEG_DESCRIPTOR(base, limit, segtype, nonsysseg, dpl, segpresent, avl, segdb, gran)        \
-              (((limit) & 0xffff)                                                              \
-               | (((unsigned long) (base) & 0xffffff) << IA32_SEG_BASE)                        \
-               | ((unsigned long) (segtype) << IA32_SEG_TYPE)                                  \
-               | ((unsigned long) (nonsysseg) << IA32_SEG_SYS)                                 \
-               | ((unsigned long) (dpl) << IA32_SEG_DPL)                                       \
-               | ((unsigned long) (segpresent) << IA32_SEG_P)                                  \
-               | ((((unsigned long) (limit) >> 16) & 0xf) << IA32_SEG_HIGH_LIMIT)              \
-               | ((unsigned long) (avl) << IA32_SEG_AVL)                                       \
-               | ((unsigned long) (segdb) << IA32_SEG_DB)                                      \
-               | ((unsigned long) (gran) << IA32_SEG_G)                                        \
-               | ((((unsigned long) (base) >> 24) & 0xff) << IA32_SEG_HIGH_BASE))
-
-#define SEG_LIM                32
-#define SEG_TYPE       52
-#define SEG_SYS                56
-#define SEG_DPL                57
-#define SEG_P          59
-#define SEG_AVL                60
-#define SEG_DB         62
-#define SEG_G          63
-
-/* Unscramble an IA-32 segment descriptor into the IA-64 format.  */
-#define IA32_SEG_UNSCRAMBLE(sd)                                                                         \
-       (   (((sd) >> IA32_SEG_BASE) & 0xffffff) | ((((sd) >> IA32_SEG_HIGH_BASE) & 0xff) << 24) \
-        | ((((sd) & 0xffff) | ((((sd) >> IA32_SEG_HIGH_LIMIT) & 0xf) << 16)) << SEG_LIM)        \
-        | ((((sd) >> IA32_SEG_TYPE) & 0xf) << SEG_TYPE)                                         \
-        | ((((sd) >> IA32_SEG_SYS) & 0x1) << SEG_SYS)                                           \
-        | ((((sd) >> IA32_SEG_DPL) & 0x3) << SEG_DPL)                                           \
-        | ((((sd) >> IA32_SEG_P) & 0x1) << SEG_P)                                               \
-        | ((((sd) >> IA32_SEG_AVL) & 0x1) << SEG_AVL)                                           \
-        | ((((sd) >> IA32_SEG_DB) & 0x1) << SEG_DB)                                             \
-        | ((((sd) >> IA32_SEG_G) & 0x1) << SEG_G))
-
-#define IA32_IOBASE    0x2000000000000000UL /* Virtual address for I/O space */
-
-#define IA32_CR0       0x80000001      /* Enable PG and PE bits */
-#define IA32_CR4       0x600           /* MMXEX and FXSR on */
-
-/*
- *  IA32 floating point control registers starting values
- */
-
-#define IA32_FSR_DEFAULT       0x55550000              /* set all tag bits */
-#define IA32_FCR_DEFAULT       0x17800000037fUL        /* extended precision, all masks */
-
-#define IA32_PTRACE_GETREGS    12
-#define IA32_PTRACE_SETREGS    13
-#define IA32_PTRACE_GETFPREGS  14
-#define IA32_PTRACE_SETFPREGS  15
-#define IA32_PTRACE_GETFPXREGS 18
-#define IA32_PTRACE_SETFPXREGS 19
-
-#define ia32_start_thread(regs,new_ip,new_sp) do {                             \
-       set_fs(USER_DS);                                                        \
-       ia64_psr(regs)->cpl = 3;        /* set user mode */                     \
-       ia64_psr(regs)->ri = 0;         /* clear return slot number */          \
-       ia64_psr(regs)->is = 1;         /* IA-32 instruction set */             \
-       regs->cr_iip = new_ip;                                                  \
-       regs->ar_rsc = 0xc;             /* enforced lazy mode, priv. level 3 */ \
-       regs->ar_rnat = 0;                                                      \
-       regs->loadrs = 0;                                                       \
-       regs->r12 = new_sp;                                                     \
-} while (0)
-
-/*
- * Local Descriptor Table (LDT) related declarations.
- */
-
-#define IA32_LDT_ENTRIES       8192            /* Maximum number of LDT entries supported. */
-#define IA32_LDT_ENTRY_SIZE    8               /* The size of each LDT entry. */
-
-#define LDT_entry_a(info) \
-       ((((info)->base_addr & 0x0000ffff) << 16) | ((info)->limit & 0x0ffff))
-
-#define LDT_entry_b(info)                              \
-       (((info)->base_addr & 0xff000000) |             \
-       (((info)->base_addr & 0x00ff0000) >> 16) |      \
-       ((info)->limit & 0xf0000) |                     \
-       (((info)->read_exec_only ^ 1) << 9) |           \
-       ((info)->contents << 10) |                      \
-       (((info)->seg_not_present ^ 1) << 15) |         \
-       ((info)->seg_32bit << 22) |                     \
-       ((info)->limit_in_pages << 23) |                \
-       ((info)->useable << 20) |                       \
-       0x7100)
-
-#define LDT_empty(info) (                      \
-       (info)->base_addr       == 0    &&      \
-       (info)->limit           == 0    &&      \
-       (info)->contents        == 0    &&      \
-       (info)->read_exec_only  == 1    &&      \
-       (info)->seg_32bit       == 0    &&      \
-       (info)->limit_in_pages  == 0    &&      \
-       (info)->seg_not_present == 1    &&      \
-       (info)->useable         == 0    )
-
-static inline void
-load_TLS (struct thread_struct *t, unsigned int cpu)
-{
-       extern unsigned long *cpu_gdt_table[NR_CPUS];
-
-       memcpy(cpu_gdt_table[cpu] + GDT_ENTRY_TLS_MIN + 0, &t->tls_array[0], sizeof(long));
-       memcpy(cpu_gdt_table[cpu] + GDT_ENTRY_TLS_MIN + 1, &t->tls_array[1], sizeof(long));
-       memcpy(cpu_gdt_table[cpu] + GDT_ENTRY_TLS_MIN + 2, &t->tls_array[2], sizeof(long));
-}
-
-struct ia32_user_desc {
-       unsigned int entry_number;
-       unsigned int base_addr;
-       unsigned int limit;
-       unsigned int seg_32bit:1;
-       unsigned int contents:2;
-       unsigned int read_exec_only:1;
-       unsigned int limit_in_pages:1;
-       unsigned int seg_not_present:1;
-       unsigned int useable:1;
-};
-
-struct linux_binprm;
-
-extern void ia32_init_addr_space (struct pt_regs *regs);
-extern int ia32_setup_arg_pages (struct linux_binprm *bprm, int exec_stack);
-extern unsigned long ia32_do_mmap (struct file *, unsigned long, unsigned long, int, int, loff_t);
-extern void ia32_load_segment_descriptors (struct task_struct *task);
-
-#define ia32f2ia64f(dst,src)                   \
-do {                                           \
-       ia64_ldfe(6,src);                       \
-       ia64_stop();                            \
-       ia64_stf_spill(dst, 6);                 \
-} while(0)
-
-#define ia64f2ia32f(dst,src)                   \
-do {                                           \
-       ia64_ldf_fill(6, src);                  \
-       ia64_stop();                            \
-       ia64_stfe(dst, 6);                      \
-} while(0)
-
-struct user_regs_struct32 {
-       __u32 ebx, ecx, edx, esi, edi, ebp, eax;
-       unsigned short ds, __ds, es, __es;
-       unsigned short fs, __fs, gs, __gs;
-       __u32 orig_eax, eip;
-       unsigned short cs, __cs;
-       __u32 eflags, esp;
-       unsigned short ss, __ss;
-};
-
-/* Prototypes for use in elfcore32.h */
-extern int save_ia32_fpstate (struct task_struct *, struct ia32_user_i387_struct __user *);
-extern int save_ia32_fpxstate (struct task_struct *, struct ia32_user_fxsr_struct __user *);
-
-#endif /* !CONFIG_IA32_SUPPORT */
-
-#endif /* _ASM_IA64_IA32_PRIV_H */
diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
deleted file mode 100644 (file)
index 045b746..0000000
+++ /dev/null
@@ -1,2765 +0,0 @@
-/*
- * sys_ia32.c: Conversion between 32bit and 64bit native syscalls. Derived from sys_sparc32.c.
- *
- * Copyright (C) 2000          VA Linux Co
- * Copyright (C) 2000          Don Dugger <n0ano@valinux.com>
- * Copyright (C) 1999          Arun Sharma <arun.sharma@intel.com>
- * Copyright (C) 1997,1998     Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- * Copyright (C) 1997          David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 2000-2003, 2005 Hewlett-Packard Co
- *     David Mosberger-Tang <davidm@hpl.hp.com>
- * Copyright (C) 2004          Gordon Jin <gordon.jin@intel.com>
- *
- * These routines maintain argument size conversion between 32bit and 64bit
- * environment.
- */
-
-#include <linux/kernel.h>
-#include <linux/syscalls.h>
-#include <linux/sysctl.h>
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/file.h>
-#include <linux/signal.h>
-#include <linux/resource.h>
-#include <linux/times.h>
-#include <linux/utsname.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/sem.h>
-#include <linux/msg.h>
-#include <linux/mm.h>
-#include <linux/shm.h>
-#include <linux/slab.h>
-#include <linux/uio.h>
-#include <linux/socket.h>
-#include <linux/quota.h>
-#include <linux/poll.h>
-#include <linux/eventpoll.h>
-#include <linux/personality.h>
-#include <linux/ptrace.h>
-#include <linux/regset.h>
-#include <linux/stat.h>
-#include <linux/ipc.h>
-#include <linux/capability.h>
-#include <linux/compat.h>
-#include <linux/vfs.h>
-#include <linux/mman.h>
-#include <linux/mutex.h>
-
-#include <asm/intrinsics.h>
-#include <asm/types.h>
-#include <asm/uaccess.h>
-#include <asm/unistd.h>
-
-#include "ia32priv.h"
-
-#include <net/scm.h>
-#include <net/sock.h>
-
-#define DEBUG  0
-
-#if DEBUG
-# define DBG(fmt...)   printk(KERN_DEBUG fmt)
-#else
-# define DBG(fmt...)
-#endif
-
-#define ROUND_UP(x,a)  ((__typeof__(x))(((unsigned long)(x) + ((a) - 1)) & ~((a) - 1)))
-
-#define OFFSET4K(a)            ((a) & 0xfff)
-#define PAGE_START(addr)       ((addr) & PAGE_MASK)
-#define MINSIGSTKSZ_IA32       2048
-
-#define high2lowuid(uid) ((uid) > 65535 ? 65534 : (uid))
-#define high2lowgid(gid) ((gid) > 65535 ? 65534 : (gid))
-
-/*
- * Anything that modifies or inspects ia32 user virtual memory must hold this semaphore
- * while doing so.
- */
-/* XXX make per-mm: */
-static DEFINE_MUTEX(ia32_mmap_mutex);
-
-asmlinkage long
-sys32_execve (char __user *name, compat_uptr_t __user *argv, compat_uptr_t __user *envp,
-             struct pt_regs *regs)
-{
-       long error;
-       char *filename;
-       unsigned long old_map_base, old_task_size, tssd;
-
-       filename = getname(name);
-       error = PTR_ERR(filename);
-       if (IS_ERR(filename))
-               return error;
-
-       old_map_base  = current->thread.map_base;
-       old_task_size = current->thread.task_size;
-       tssd = ia64_get_kr(IA64_KR_TSSD);
-
-       /* we may be exec'ing a 64-bit process: reset map base, task-size, and io-base: */
-       current->thread.map_base  = DEFAULT_MAP_BASE;
-       current->thread.task_size = DEFAULT_TASK_SIZE;
-       ia64_set_kr(IA64_KR_IO_BASE, current->thread.old_iob);
-       ia64_set_kr(IA64_KR_TSSD, current->thread.old_k1);
-
-       error = compat_do_execve(filename, argv, envp, regs);
-       putname(filename);
-
-       if (error < 0) {
-               /* oops, execve failed, switch back to old values... */
-               ia64_set_kr(IA64_KR_IO_BASE, IA32_IOBASE);
-               ia64_set_kr(IA64_KR_TSSD, tssd);
-               current->thread.map_base  = old_map_base;
-               current->thread.task_size = old_task_size;
-       }
-
-       return error;
-}
-
-
-#if PAGE_SHIFT > IA32_PAGE_SHIFT
-
-
-static int
-get_page_prot (struct vm_area_struct *vma, unsigned long addr)
-{
-       int prot = 0;
-
-       if (!vma || vma->vm_start > addr)
-               return 0;
-
-       if (vma->vm_flags & VM_READ)
-               prot |= PROT_READ;
-       if (vma->vm_flags & VM_WRITE)
-               prot |= PROT_WRITE;
-       if (vma->vm_flags & VM_EXEC)
-               prot |= PROT_EXEC;
-       return prot;
-}
-
-/*
- * Map a subpage by creating an anonymous page that contains the union of the old page and
- * the subpage.
- */
-static unsigned long
-mmap_subpage (struct file *file, unsigned long start, unsigned long end, int prot, int flags,
-             loff_t off)
-{
-       void *page = NULL;
-       struct inode *inode;
-       unsigned long ret = 0;
-       struct vm_area_struct *vma = find_vma(current->mm, start);
-       int old_prot = get_page_prot(vma, start);
-
-       DBG("mmap_subpage(file=%p,start=0x%lx,end=0x%lx,prot=%x,flags=%x,off=0x%llx)\n",
-           file, start, end, prot, flags, off);
-
-
-       /* Optimize the case where the old mmap and the new mmap are both anonymous */
-       if ((old_prot & PROT_WRITE) && (flags & MAP_ANONYMOUS) && !vma->vm_file) {
-               if (clear_user((void __user *) start, end - start)) {
-                       ret = -EFAULT;
-                       goto out;
-               }
-               goto skip_mmap;
-       }
-
-       page = (void *) get_zeroed_page(GFP_KERNEL);
-       if (!page)
-               return -ENOMEM;
-
-       if (old_prot)
-               copy_from_user(page, (void __user *) PAGE_START(start), PAGE_SIZE);
-
-       down_write(&current->mm->mmap_sem);
-       {
-               ret = do_mmap(NULL, PAGE_START(start), PAGE_SIZE, prot | PROT_WRITE,
-                             flags | MAP_FIXED | MAP_ANONYMOUS, 0);
-       }
-       up_write(&current->mm->mmap_sem);
-
-       if (IS_ERR((void *) ret))
-               goto out;
-
-       if (old_prot) {
-               /* copy back the old page contents.  */
-               if (offset_in_page(start))
-                       copy_to_user((void __user *) PAGE_START(start), page,
-                                    offset_in_page(start));
-               if (offset_in_page(end))
-                       copy_to_user((void __user *) end, page + offset_in_page(end),
-                                    PAGE_SIZE - offset_in_page(end));
-       }
-
-       if (!(flags & MAP_ANONYMOUS)) {
-               /* read the file contents */
-               inode = file->f_path.dentry->d_inode;
-               if (!inode->i_fop || !file->f_op->read
-                   || ((*file->f_op->read)(file, (char __user *) start, end - start, &off) < 0))
-               {
-                       ret = -EINVAL;
-                       goto out;
-               }
-       }
-
- skip_mmap:
-       if (!(prot & PROT_WRITE))
-               ret = sys_mprotect(PAGE_START(start), PAGE_SIZE, prot | old_prot);
-  out:
-       if (page)
-               free_page((unsigned long) page);
-       return ret;
-}
-
-/* SLAB cache for ia64_partial_page structures */
-struct kmem_cache *ia64_partial_page_cachep;
-
-/*
- * init ia64_partial_page_list.
- * return 0 means kmalloc fail.
- */
-struct ia64_partial_page_list*
-ia32_init_pp_list(void)
-{
-       struct ia64_partial_page_list *p;
-
-       if ((p = kmalloc(sizeof(*p), GFP_KERNEL)) == NULL)
-               return p;
-       p->pp_head = NULL;
-       p->ppl_rb = RB_ROOT;
-       p->pp_hint = NULL;
-       atomic_set(&p->pp_count, 1);
-       return p;
-}
-
-/*
- * Search for the partial page with @start in partial page list @ppl.
- * If finds the partial page, return the found partial page.
- * Else, return 0 and provide @pprev, @rb_link, @rb_parent to
- * be used by later __ia32_insert_pp().
- */
-static struct ia64_partial_page *
-__ia32_find_pp(struct ia64_partial_page_list *ppl, unsigned int start,
-       struct ia64_partial_page **pprev, struct rb_node ***rb_link,
-       struct rb_node **rb_parent)
-{
-       struct ia64_partial_page *pp;
-       struct rb_node **__rb_link, *__rb_parent, *rb_prev;
-
-       pp = ppl->pp_hint;
-       if (pp && pp->base == start)
-               return pp;
-
-       __rb_link = &ppl->ppl_rb.rb_node;
-       rb_prev = __rb_parent = NULL;
-
-       while (*__rb_link) {
-               __rb_parent = *__rb_link;
-               pp = rb_entry(__rb_parent, struct ia64_partial_page, pp_rb);
-
-               if (pp->base == start) {
-                       ppl->pp_hint = pp;
-                       return pp;
-               } else if (pp->base < start) {
-                       rb_prev = __rb_parent;
-                       __rb_link = &__rb_parent->rb_right;
-               } else {
-                       __rb_link = &__rb_parent->rb_left;
-               }
-       }
-
-       *rb_link = __rb_link;
-       *rb_parent = __rb_parent;
-       *pprev = NULL;
-       if (rb_prev)
-               *pprev = rb_entry(rb_prev, struct ia64_partial_page, pp_rb);
-       return NULL;
-}
-
-/*
- * insert @pp into @ppl.
- */
-static void
-__ia32_insert_pp(struct ia64_partial_page_list *ppl,
-       struct ia64_partial_page *pp, struct ia64_partial_page *prev,
-       struct rb_node **rb_link, struct rb_node *rb_parent)
-{
-       /* link list */
-       if (prev) {
-               pp->next = prev->next;
-               prev->next = pp;
-       } else {
-               ppl->pp_head = pp;
-               if (rb_parent)
-                       pp->next = rb_entry(rb_parent,
-                               struct ia64_partial_page, pp_rb);
-               else
-                       pp->next = NULL;
-       }
-
-       /* link rb */
-       rb_link_node(&pp->pp_rb, rb_parent, rb_link);
-       rb_insert_color(&pp->pp_rb, &ppl->ppl_rb);
-
-       ppl->pp_hint = pp;
-}
-
-/*
- * delete @pp from partial page list @ppl.
- */
-static void
-__ia32_delete_pp(struct ia64_partial_page_list *ppl,
-       struct ia64_partial_page *pp, struct ia64_partial_page *prev)
-{
-       if (prev) {
-               prev->next = pp->next;
-               if (ppl->pp_hint == pp)
-                       ppl->pp_hint = prev;
-       } else {
-               ppl->pp_head = pp->next;
-               if (ppl->pp_hint == pp)
-                       ppl->pp_hint = pp->next;
-       }
-       rb_erase(&pp->pp_rb, &ppl->ppl_rb);
-       kmem_cache_free(ia64_partial_page_cachep, pp);
-}
-
-static struct ia64_partial_page *
-__pp_prev(struct ia64_partial_page *pp)
-{
-       struct rb_node *prev = rb_prev(&pp->pp_rb);
-       if (prev)
-               return rb_entry(prev, struct ia64_partial_page, pp_rb);
-       else
-               return NULL;
-}
-
-/*
- * Delete partial pages with address between @start and @end.
- * @start and @end are page aligned.
- */
-static void
-__ia32_delete_pp_range(unsigned int start, unsigned int end)
-{
-       struct ia64_partial_page *pp, *prev;
-       struct rb_node **rb_link, *rb_parent;
-
-       if (start >= end)
-               return;
-
-       pp = __ia32_find_pp(current->thread.ppl, start, &prev,
-                                       &rb_link, &rb_parent);
-       if (pp)
-               prev = __pp_prev(pp);
-       else {
-               if (prev)
-                       pp = prev->next;
-               else
-                       pp = current->thread.ppl->pp_head;
-       }
-
-       while (pp && pp->base < end) {
-               struct ia64_partial_page *tmp = pp->next;
-               __ia32_delete_pp(current->thread.ppl, pp, prev);
-               pp = tmp;
-       }
-}
-
-/*
- * Set the range between @start and @end in bitmap.
- * @start and @end should be IA32 page aligned and in the same IA64 page.
- */
-static int
-__ia32_set_pp(unsigned int start, unsigned int end, int flags)
-{
-       struct ia64_partial_page *pp, *prev;
-       struct rb_node ** rb_link, *rb_parent;
-       unsigned int pstart, start_bit, end_bit, i;
-
-       pstart = PAGE_START(start);
-       start_bit = (start % PAGE_SIZE) / IA32_PAGE_SIZE;
-       end_bit = (end % PAGE_SIZE) / IA32_PAGE_SIZE;
-       if (end_bit == 0)
-               end_bit = PAGE_SIZE / IA32_PAGE_SIZE;
-       pp = __ia32_find_pp(current->thread.ppl, pstart, &prev,
-                                       &rb_link, &rb_parent);
-       if (pp) {
-               for (i = start_bit; i < end_bit; i++)
-                       set_bit(i, &pp->bitmap);
-               /*
-                * Check: if this partial page has been set to a full page,
-                * then delete it.
-                */
-               if (find_first_zero_bit(&pp->bitmap, sizeof(pp->bitmap)*8) >=
-                               PAGE_SIZE/IA32_PAGE_SIZE) {
-                       __ia32_delete_pp(current->thread.ppl, pp, __pp_prev(pp));
-               }
-               return 0;
-       }
-
-       /*
-        * MAP_FIXED may lead to overlapping mmap.
-        * In this case, the requested mmap area may already mmaped as a full
-        * page. So check vma before adding a new partial page.
-        */
-       if (flags & MAP_FIXED) {
-               struct vm_area_struct *vma = find_vma(current->mm, pstart);
-               if (vma && vma->vm_start <= pstart)
-                       return 0;
-       }
-
-       /* new a ia64_partial_page */
-       pp = kmem_cache_alloc(ia64_partial_page_cachep, GFP_KERNEL);
-       if (!pp)
-               return -ENOMEM;
-       pp->base = pstart;
-       pp->bitmap = 0;
-       for (i=start_bit; i<end_bit; i++)
-               set_bit(i, &(pp->bitmap));
-       pp->next = NULL;
-       __ia32_insert_pp(current->thread.ppl, pp, prev, rb_link, rb_parent);
-       return 0;
-}
-
-/*
- * @start and @end should be IA32 page aligned, but don't need to be in the
- * same IA64 page. Split @start and @end to make sure they're in the same IA64
- * page, then call __ia32_set_pp().
- */
-static void
-ia32_set_pp(unsigned int start, unsigned int end, int flags)
-{
-       down_write(&current->mm->mmap_sem);
-       if (flags & MAP_FIXED) {
-               /*
-                * MAP_FIXED may lead to overlapping mmap. When this happens,
-                * a series of complete IA64 pages results in deletion of
-                * old partial pages in that range.
-                */
-               __ia32_delete_pp_range(PAGE_ALIGN(start), PAGE_START(end));
-       }
-
-       if (end < PAGE_ALIGN(start)) {
-               __ia32_set_pp(start, end, flags);
-       } else {
-               if (offset_in_page(start))
-                       __ia32_set_pp(start, PAGE_ALIGN(start), flags);
-               if (offset_in_page(end))
-                       __ia32_set_pp(PAGE_START(end), end, flags);
-       }
-       up_write(&current->mm->mmap_sem);
-}
-
-/*
- * Unset the range between @start and @end in bitmap.
- * @start and @end should be IA32 page aligned and in the same IA64 page.
- * After doing that, if the bitmap is 0, then free the page and return 1,
- *     else return 0;
- * If not find the partial page in the list, then
- *     If the vma exists, then the full page is set to a partial page;
- *     Else return -ENOMEM.
- */
-static int
-__ia32_unset_pp(unsigned int start, unsigned int end)
-{
-       struct ia64_partial_page *pp, *prev;
-       struct rb_node ** rb_link, *rb_parent;
-       unsigned int pstart, start_bit, end_bit, i;
-       struct vm_area_struct *vma;
-
-       pstart = PAGE_START(start);
-       start_bit = (start % PAGE_SIZE) / IA32_PAGE_SIZE;
-       end_bit = (end % PAGE_SIZE) / IA32_PAGE_SIZE;
-       if (end_bit == 0)
-               end_bit = PAGE_SIZE / IA32_PAGE_SIZE;
-
-       pp = __ia32_find_pp(current->thread.ppl, pstart, &prev,
-                                       &rb_link, &rb_parent);
-       if (pp) {
-               for (i = start_bit; i < end_bit; i++)
-                       clear_bit(i, &pp->bitmap);
-               if (pp->bitmap == 0) {
-                       __ia32_delete_pp(current->thread.ppl, pp, __pp_prev(pp));
-                       return 1;
-               }
-               return 0;
-       }
-
-       vma = find_vma(current->mm, pstart);
-       if (!vma || vma->vm_start > pstart) {
-               return -ENOMEM;
-       }
-
-       /* new a ia64_partial_page */
-       pp = kmem_cache_alloc(ia64_partial_page_cachep, GFP_KERNEL);
-       if (!pp)
-               return -ENOMEM;
-       pp->base = pstart;
-       pp->bitmap = 0;
-       for (i = 0; i < start_bit; i++)
-               set_bit(i, &(pp->bitmap));
-       for (i = end_bit; i < PAGE_SIZE / IA32_PAGE_SIZE; i++)
-               set_bit(i, &(pp->bitmap));
-       pp->next = NULL;
-       __ia32_insert_pp(current->thread.ppl, pp, prev, rb_link, rb_parent);
-       return 0;
-}
-
-/*
- * Delete pp between PAGE_ALIGN(start) and PAGE_START(end) by calling
- * __ia32_delete_pp_range(). Unset possible partial pages by calling
- * __ia32_unset_pp().
- * The returned value see __ia32_unset_pp().
- */
-static int
-ia32_unset_pp(unsigned int *startp, unsigned int *endp)
-{
-       unsigned int start = *startp, end = *endp;
-       int ret = 0;
-
-       down_write(&current->mm->mmap_sem);
-
-       __ia32_delete_pp_range(PAGE_ALIGN(start), PAGE_START(end));
-
-       if (end < PAGE_ALIGN(start)) {
-               ret = __ia32_unset_pp(start, end);
-               if (ret == 1) {
-                       *startp = PAGE_START(start);
-                       *endp = PAGE_ALIGN(end);
-               }
-               if (ret == 0) {
-                       /* to shortcut sys_munmap() in sys32_munmap() */
-                       *startp = PAGE_START(start);
-                       *endp = PAGE_START(end);
-               }
-       } else {
-               if (offset_in_page(start)) {
-                       ret = __ia32_unset_pp(start, PAGE_ALIGN(start));
-                       if (ret == 1)
-                               *startp = PAGE_START(start);
-                       if (ret == 0)
-                               *startp = PAGE_ALIGN(start);
-                       if (ret < 0)
-                               goto out;
-               }
-               if (offset_in_page(end)) {
-                       ret = __ia32_unset_pp(PAGE_START(end), end);
-                       if (ret == 1)
-                               *endp = PAGE_ALIGN(end);
-                       if (ret == 0)
-                               *endp = PAGE_START(end);
-               }
-       }
-
- out:
-       up_write(&current->mm->mmap_sem);
-       return ret;
-}
-
-/*
- * Compare the range between @start and @end with bitmap in partial page.
- * @start and @end should be IA32 page aligned and in the same IA64 page.
- */
-static int
-__ia32_compare_pp(unsigned int start, unsigned int end)
-{
-       struct ia64_partial_page *pp, *prev;
-       struct rb_node ** rb_link, *rb_parent;
-       unsigned int pstart, start_bit, end_bit, size;
-       unsigned int first_bit, next_zero_bit;  /* the first range in bitmap */
-
-       pstart = PAGE_START(start);
-
-       pp = __ia32_find_pp(current->thread.ppl, pstart, &prev,
-                                       &rb_link, &rb_parent);
-       if (!pp)
-               return 1;
-
-       start_bit = (start % PAGE_SIZE) / IA32_PAGE_SIZE;
-       end_bit = (end % PAGE_SIZE) / IA32_PAGE_SIZE;
-       size = sizeof(pp->bitmap) * 8;
-       first_bit = find_first_bit(&pp->bitmap, size);
-       next_zero_bit = find_next_zero_bit(&pp->bitmap, size, first_bit);
-       if ((start_bit < first_bit) || (end_bit > next_zero_bit)) {
-               /* exceeds the first range in bitmap */
-               return -ENOMEM;
-       } else if ((start_bit == first_bit) && (end_bit == next_zero_bit)) {
-               first_bit = find_next_bit(&pp->bitmap, size, next_zero_bit);
-               if ((next_zero_bit < first_bit) && (first_bit < size))
-                       return 1;       /* has next range */
-               else
-                       return 0;       /* no next range */
-       } else
-               return 1;
-}
-
-/*
- * @start and @end should be IA32 page aligned, but don't need to be in the
- * same IA64 page. Split @start and @end to make sure they're in the same IA64
- * page, then call __ia32_compare_pp().
- *
- * Take this as example: the range is the 1st and 2nd 4K page.
- * Return 0 if they fit bitmap exactly, i.e. bitmap = 00000011;
- * Return 1 if the range doesn't cover whole bitmap, e.g. bitmap = 00001111;
- * Return -ENOMEM if the range exceeds the bitmap, e.g. bitmap = 00000001 or
- *     bitmap = 00000101.
- */
-static int
-ia32_compare_pp(unsigned int *startp, unsigned int *endp)
-{
-       unsigned int start = *startp, end = *endp;
-       int retval = 0;
-
-       down_write(&current->mm->mmap_sem);
-
-       if (end < PAGE_ALIGN(start)) {
-               retval = __ia32_compare_pp(start, end);
-               if (retval == 0) {
-                       *startp = PAGE_START(start);
-                       *endp = PAGE_ALIGN(end);
-               }
-       } else {
-               if (offset_in_page(start)) {
-                       retval = __ia32_compare_pp(start,
-                                                  PAGE_ALIGN(start));
-                       if (retval == 0)
-                               *startp = PAGE_START(start);
-                       if (retval < 0)
-                               goto out;
-               }
-               if (offset_in_page(end)) {
-                       retval = __ia32_compare_pp(PAGE_START(end), end);
-                       if (retval == 0)
-                               *endp = PAGE_ALIGN(end);
-               }
-       }
-
- out:
-       up_write(&current->mm->mmap_sem);
-       return retval;
-}
-
-static void
-__ia32_drop_pp_list(struct ia64_partial_page_list *ppl)
-{
-       struct ia64_partial_page *pp = ppl->pp_head;
-
-       while (pp) {
-               struct ia64_partial_page *next = pp->next;
-               kmem_cache_free(ia64_partial_page_cachep, pp);
-               pp = next;
-       }
-
-       kfree(ppl);
-}
-
-void
-ia32_drop_ia64_partial_page_list(struct task_struct *task)
-{
-       struct ia64_partial_page_list* ppl = task->thread.ppl;
-
-       if (ppl && atomic_dec_and_test(&ppl->pp_count))
-               __ia32_drop_pp_list(ppl);
-}
-
-/*
- * Copy current->thread.ppl to ppl (already initialized).
- */
-static int
-__ia32_copy_pp_list(struct ia64_partial_page_list *ppl)
-{
-       struct ia64_partial_page *pp, *tmp, *prev;
-       struct rb_node **rb_link, *rb_parent;
-
-       ppl->pp_head = NULL;
-       ppl->pp_hint = NULL;
-       ppl->ppl_rb = RB_ROOT;
-       rb_link = &ppl->ppl_rb.rb_node;
-       rb_parent = NULL;
-       prev = NULL;
-
-       for (pp = current->thread.ppl->pp_head; pp; pp = pp->next) {
-               tmp = kmem_cache_alloc(ia64_partial_page_cachep, GFP_KERNEL);
-               if (!tmp)
-                       return -ENOMEM;
-               *tmp = *pp;
-               __ia32_insert_pp(ppl, tmp, prev, rb_link, rb_parent);
-               prev = tmp;
-               rb_link = &tmp->pp_rb.rb_right;
-               rb_parent = &tmp->pp_rb;
-       }
-       return 0;
-}
-
-int
-ia32_copy_ia64_partial_page_list(struct task_struct *p,
-                               unsigned long clone_flags)
-{
-       int retval = 0;
-
-       if (clone_flags & CLONE_VM) {
-               atomic_inc(&current->thread.ppl->pp_count);
-               p->thread.ppl = current->thread.ppl;
-       } else {
-               p->thread.ppl = ia32_init_pp_list();
-               if (!p->thread.ppl)
-                       return -ENOMEM;
-               down_write(&current->mm->mmap_sem);
-               {
-                       retval = __ia32_copy_pp_list(p->thread.ppl);
-               }
-               up_write(&current->mm->mmap_sem);
-       }
-
-       return retval;
-}
-
-static unsigned long
-emulate_mmap (struct file *file, unsigned long start, unsigned long len, int prot, int flags,
-             loff_t off)
-{
-       unsigned long tmp, end, pend, pstart, ret, is_congruent, fudge = 0;
-       struct inode *inode;
-       loff_t poff;
-
-       end = start + len;
-       pstart = PAGE_START(start);
-       pend = PAGE_ALIGN(end);
-
-       if (flags & MAP_FIXED) {
-               ia32_set_pp((unsigned int)start, (unsigned int)end, flags);
-               if (start > pstart) {
-                       if (flags & MAP_SHARED)
-                               printk(KERN_INFO
-                                      "%s(%d): emulate_mmap() can't share head (addr=0x%lx)\n",
-                                      current->comm, task_pid_nr(current), start);
-                       ret = mmap_subpage(file, start, min(PAGE_ALIGN(start), end), prot, flags,
-                                          off);
-                       if (IS_ERR((void *) ret))
-                               return ret;
-                       pstart += PAGE_SIZE;
-                       if (pstart >= pend)
-                               goto out;       /* done */
-               }
-               if (end < pend) {
-                       if (flags & MAP_SHARED)
-                               printk(KERN_INFO
-                                      "%s(%d): emulate_mmap() can't share tail (end=0x%lx)\n",
-                                      current->comm, task_pid_nr(current), end);
-                       ret = mmap_subpage(file, max(start, PAGE_START(end)), end, prot, flags,
-                                          (off + len) - offset_in_page(end));
-                       if (IS_ERR((void *) ret))
-                               return ret;
-                       pend -= PAGE_SIZE;
-                       if (pstart >= pend)
-                               goto out;       /* done */
-               }
-       } else {
-               /*
-                * If a start address was specified, use it if the entire rounded out area
-                * is available.
-                */
-               if (start && !pstart)
-                       fudge = 1;      /* handle case of mapping to range (0,PAGE_SIZE) */
-               tmp = arch_get_unmapped_area(file, pstart - fudge, pend - pstart, 0, flags);
-               if (tmp != pstart) {
-                       pstart = tmp;
-                       start = pstart + offset_in_page(off);   /* make start congruent with off */
-                       end = start + len;
-                       pend = PAGE_ALIGN(end);
-               }
-       }
-
-       poff = off + (pstart - start);  /* note: (pstart - start) may be negative */
-       is_congruent = (flags & MAP_ANONYMOUS) || (offset_in_page(poff) == 0);
-
-       if ((flags & MAP_SHARED) && !is_congruent)
-               printk(KERN_INFO "%s(%d): emulate_mmap() can't share contents of incongruent mmap "
-                      "(addr=0x%lx,off=0x%llx)\n", current->comm, task_pid_nr(current), start, off);
-
-       DBG("mmap_body: mapping [0x%lx-0x%lx) %s with poff 0x%llx\n", pstart, pend,
-           is_congruent ? "congruent" : "not congruent", poff);
-
-       down_write(&current->mm->mmap_sem);
-       {
-               if (!(flags & MAP_ANONYMOUS) && is_congruent)
-                       ret = do_mmap(file, pstart, pend - pstart, prot, flags | MAP_FIXED, poff);
-               else
-                       ret = do_mmap(NULL, pstart, pend - pstart,
-                                     prot | ((flags & MAP_ANONYMOUS) ? 0 : PROT_WRITE),
-                                     flags | MAP_FIXED | MAP_ANONYMOUS, 0);
-       }
-       up_write(&current->mm->mmap_sem);
-
-       if (IS_ERR((void *) ret))
-               return ret;
-
-       if (!is_congruent) {
-               /* read the file contents */
-               inode = file->f_path.dentry->d_inode;
-               if (!inode->i_fop || !file->f_op->read
-                   || ((*file->f_op->read)(file, (char __user *) pstart, pend - pstart, &poff)
-                       < 0))
-               {
-                       sys_munmap(pstart, pend - pstart);
-                       return -EINVAL;
-               }
-               if (!(prot & PROT_WRITE) && sys_mprotect(pstart, pend - pstart, prot) < 0)
-                       return -EINVAL;
-       }
-
-       if (!(flags & MAP_FIXED))
-               ia32_set_pp((unsigned int)start, (unsigned int)end, flags);
-out:
-       return start;
-}
-
-#endif /* PAGE_SHIFT > IA32_PAGE_SHIFT */
-
-static inline unsigned int
-get_prot32 (unsigned int prot)
-{
-       if (prot & PROT_WRITE)
-               /* on x86, PROT_WRITE implies PROT_READ which implies PROT_EEC */
-               prot |= PROT_READ | PROT_WRITE | PROT_EXEC;
-       else if (prot & (PROT_READ | PROT_EXEC))
-               /* on x86, there is no distinction between PROT_READ and PROT_EXEC */
-               prot |= (PROT_READ | PROT_EXEC);
-
-       return prot;
-}
-
-unsigned long
-ia32_do_mmap (struct file *file, unsigned long addr, unsigned long len, int prot, int flags,
-             loff_t offset)
-{
-       DBG("ia32_do_mmap(file=%p,addr=0x%lx,len=0x%lx,prot=%x,flags=%x,offset=0x%llx)\n",
-           file, addr, len, prot, flags, offset);
-
-       if (file && (!file->f_op || !file->f_op->mmap))
-               return -ENODEV;
-
-       len = IA32_PAGE_ALIGN(len);
-       if (len == 0)
-               return addr;
-
-       if (len > IA32_PAGE_OFFSET || addr > IA32_PAGE_OFFSET - len)
-       {
-               if (flags & MAP_FIXED)
-                       return -ENOMEM;
-               else
-               return -EINVAL;
-       }
-
-       if (OFFSET4K(offset))
-               return -EINVAL;
-
-       prot = get_prot32(prot);
-
-       if (flags & MAP_HUGETLB)
-               return -ENOMEM;
-
-#if PAGE_SHIFT > IA32_PAGE_SHIFT
-       mutex_lock(&ia32_mmap_mutex);
-       {
-               addr = emulate_mmap(file, addr, len, prot, flags, offset);
-       }
-       mutex_unlock(&ia32_mmap_mutex);
-#else
-       down_write(&current->mm->mmap_sem);
-       {
-               addr = do_mmap(file, addr, len, prot, flags, offset);
-       }
-       up_write(&current->mm->mmap_sem);
-#endif
-       DBG("ia32_do_mmap: returning 0x%lx\n", addr);
-       return addr;
-}
-
-/*
- * Linux/i386 didn't use to be able to handle more than 4 system call parameters, so these
- * system calls used a memory block for parameter passing..
- */
-
-struct mmap_arg_struct {
-       unsigned int addr;
-       unsigned int len;
-       unsigned int prot;
-       unsigned int flags;
-       unsigned int fd;
-       unsigned int offset;
-};
-
-asmlinkage long
-sys32_mmap (struct mmap_arg_struct __user *arg)
-{
-       struct mmap_arg_struct a;
-       struct file *file = NULL;
-       unsigned long addr;
-       int flags;
-
-       if (copy_from_user(&a, arg, sizeof(a)))
-               return -EFAULT;
-
-       if (OFFSET4K(a.offset))
-               return -EINVAL;
-
-       flags = a.flags;
-
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-       if (!(flags & MAP_ANONYMOUS)) {
-               file = fget(a.fd);
-               if (!file)
-                       return -EBADF;
-       }
-
-       addr = ia32_do_mmap(file, a.addr, a.len, a.prot, flags, a.offset);
-
-       if (file)
-               fput(file);
-       return addr;
-}
-
-asmlinkage long
-sys32_mmap2 (unsigned int addr, unsigned int len, unsigned int prot, unsigned int flags,
-            unsigned int fd, unsigned int pgoff)
-{
-       struct file *file = NULL;
-       unsigned long retval;
-
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-       if (!(flags & MAP_ANONYMOUS)) {
-               file = fget(fd);
-               if (!file)
-                       return -EBADF;
-       }
-
-       retval = ia32_do_mmap(file, addr, len, prot, flags,
-                             (unsigned long) pgoff << IA32_PAGE_SHIFT);
-
-       if (file)
-               fput(file);
-       return retval;
-}
-
-asmlinkage long
-sys32_munmap (unsigned int start, unsigned int len)
-{
-       unsigned int end = start + len;
-       long ret;
-
-#if PAGE_SHIFT <= IA32_PAGE_SHIFT
-       ret = sys_munmap(start, end - start);
-#else
-       if (OFFSET4K(start))
-               return -EINVAL;
-
-       end = IA32_PAGE_ALIGN(end);
-       if (start >= end)
-               return -EINVAL;
-
-       ret = ia32_unset_pp(&start, &end);
-       if (ret < 0)
-               return ret;
-
-       if (start >= end)
-               return 0;
-
-       mutex_lock(&ia32_mmap_mutex);
-       ret = sys_munmap(start, end - start);
-       mutex_unlock(&ia32_mmap_mutex);
-#endif
-       return ret;
-}
-
-#if PAGE_SHIFT > IA32_PAGE_SHIFT
-
-/*
- * When mprotect()ing a partial page, we set the permission to the union of the old
- * settings and the new settings.  In other words, it's only possible to make access to a
- * partial page less restrictive.
- */
-static long
-mprotect_subpage (unsigned long address, int new_prot)
-{
-       int old_prot;
-       struct vm_area_struct *vma;
-
-       if (new_prot == PROT_NONE)
-               return 0;               /* optimize case where nothing changes... */
-       vma = find_vma(current->mm, address);
-       old_prot = get_page_prot(vma, address);
-       return sys_mprotect(address, PAGE_SIZE, new_prot | old_prot);
-}
-
-#endif /* PAGE_SHIFT > IA32_PAGE_SHIFT */
-
-asmlinkage long
-sys32_mprotect (unsigned int start, unsigned int len, int prot)
-{
-       unsigned int end = start + len;
-#if PAGE_SHIFT > IA32_PAGE_SHIFT
-       long retval = 0;
-#endif
-
-       prot = get_prot32(prot);
-
-#if PAGE_SHIFT <= IA32_PAGE_SHIFT
-       return sys_mprotect(start, end - start, prot);
-#else
-       if (OFFSET4K(start))
-               return -EINVAL;
-
-       end = IA32_PAGE_ALIGN(end);
-       if (end < start)
-               return -EINVAL;
-
-       retval = ia32_compare_pp(&start, &end);
-
-       if (retval < 0)
-               return retval;
-
-       mutex_lock(&ia32_mmap_mutex);
-       {
-               if (offset_in_page(start)) {
-                       /* start address is 4KB aligned but not page aligned. */
-                       retval = mprotect_subpage(PAGE_START(start), prot);
-                       if (retval < 0)
-                               goto out;
-
-                       start = PAGE_ALIGN(start);
-                       if (start >= end)
-                               goto out;       /* retval is already zero... */
-               }
-
-               if (offset_in_page(end)) {
-                       /* end address is 4KB aligned but not page aligned. */
-                       retval = mprotect_subpage(PAGE_START(end), prot);
-                       if (retval < 0)
-                               goto out;
-
-                       end = PAGE_START(end);
-               }
-               retval = sys_mprotect(start, end - start, prot);
-       }
-  out:
-       mutex_unlock(&ia32_mmap_mutex);
-       return retval;
-#endif
-}
-
-asmlinkage long
-sys32_mremap (unsigned int addr, unsigned int old_len, unsigned int new_len,
-               unsigned int flags, unsigned int new_addr)
-{
-       long ret;
-
-#if PAGE_SHIFT <= IA32_PAGE_SHIFT
-       ret = sys_mremap(addr, old_len, new_len, flags, new_addr);
-#else
-       unsigned int old_end, new_end;
-
-       if (OFFSET4K(addr))
-               return -EINVAL;
-
-       old_len = IA32_PAGE_ALIGN(old_len);
-       new_len = IA32_PAGE_ALIGN(new_len);
-       old_end = addr + old_len;
-       new_end = addr + new_len;
-
-       if (!new_len)
-               return -EINVAL;
-
-       if ((flags & MREMAP_FIXED) && (OFFSET4K(new_addr)))
-               return -EINVAL;
-
-       if (old_len >= new_len) {
-               ret = sys32_munmap(addr + new_len, old_len - new_len);
-               if (ret && old_len != new_len)
-                       return ret;
-               ret = addr;
-               if (!(flags & MREMAP_FIXED) || (new_addr == addr))
-                       return ret;
-               old_len = new_len;
-       }
-
-       addr = PAGE_START(addr);
-       old_len = PAGE_ALIGN(old_end) - addr;
-       new_len = PAGE_ALIGN(new_end) - addr;
-
-       mutex_lock(&ia32_mmap_mutex);
-       ret = sys_mremap(addr, old_len, new_len, flags, new_addr);
-       mutex_unlock(&ia32_mmap_mutex);
-
-       if ((ret >= 0) && (old_len < new_len)) {
-               /* mremap expanded successfully */
-               ia32_set_pp(old_end, new_end, flags);
-       }
-#endif
-       return ret;
-}
-
-asmlinkage unsigned long
-sys32_alarm (unsigned int seconds)
-{
-       return alarm_setitimer(seconds);
-}
-
-struct sel_arg_struct {
-       unsigned int n;
-       unsigned int inp;
-       unsigned int outp;
-       unsigned int exp;
-       unsigned int tvp;
-};
-
-asmlinkage long
-sys32_old_select (struct sel_arg_struct __user *arg)
-{
-       struct sel_arg_struct a;
-
-       if (copy_from_user(&a, arg, sizeof(a)))
-               return -EFAULT;
-       return compat_sys_select(a.n, compat_ptr(a.inp), compat_ptr(a.outp),
-                                compat_ptr(a.exp), compat_ptr(a.tvp));
-}
-
-#define SEMOP           1
-#define SEMGET          2
-#define SEMCTL          3
-#define SEMTIMEDOP      4
-#define MSGSND         11
-#define MSGRCV         12
-#define MSGGET         13
-#define MSGCTL         14
-#define SHMAT          21
-#define SHMDT          22
-#define SHMGET         23
-#define SHMCTL         24
-
-asmlinkage long
-sys32_ipc(u32 call, int first, int second, int third, u32 ptr, u32 fifth)
-{
-       int version;
-
-       version = call >> 16; /* hack for backward compatibility */
-       call &= 0xffff;
-
-       switch (call) {
-             case SEMTIMEDOP:
-               if (fifth)
-                       return compat_sys_semtimedop(first, compat_ptr(ptr),
-                               second, compat_ptr(fifth));
-               /* else fall through for normal semop() */
-             case SEMOP:
-               /* struct sembuf is the same on 32 and 64bit :)) */
-               return sys_semtimedop(first, compat_ptr(ptr), second,
-                                     NULL);
-             case SEMGET:
-               return sys_semget(first, second, third);
-             case SEMCTL:
-               return compat_sys_semctl(first, second, third, compat_ptr(ptr));
-
-             case MSGSND:
-               return compat_sys_msgsnd(first, second, third, compat_ptr(ptr));
-             case MSGRCV:
-               return compat_sys_msgrcv(first, second, fifth, third, version, compat_ptr(ptr));
-             case MSGGET:
-               return sys_msgget((key_t) first, second);
-             case MSGCTL:
-               return compat_sys_msgctl(first, second, compat_ptr(ptr));
-
-             case SHMAT:
-               return compat_sys_shmat(first, second, third, version, compat_ptr(ptr));
-               break;
-             case SHMDT:
-               return sys_shmdt(compat_ptr(ptr));
-             case SHMGET:
-               return sys_shmget(first, (unsigned)second, third);
-             case SHMCTL:
-               return compat_sys_shmctl(first, second, compat_ptr(ptr));
-
-             default:
-               return -ENOSYS;
-       }
-       return -EINVAL;
-}
-
-asmlinkage long
-compat_sys_wait4 (compat_pid_t pid, compat_uint_t * stat_addr, int options,
-                struct compat_rusage *ru);
-
-asmlinkage long
-sys32_waitpid (int pid, unsigned int *stat_addr, int options)
-{
-       return compat_sys_wait4(pid, stat_addr, options, NULL);
-}
-
-/*
- *  The order in which registers are stored in the ptrace regs structure
- */
-#define PT_EBX 0
-#define PT_ECX 1
-#define PT_EDX 2
-#define PT_ESI 3
-#define PT_EDI 4
-#define PT_EBP 5
-#define PT_EAX 6
-#define PT_DS  7
-#define PT_ES  8
-#define PT_FS  9
-#define PT_GS  10
-#define PT_ORIG_EAX 11
-#define PT_EIP 12
-#define PT_CS  13
-#define PT_EFL 14
-#define PT_UESP        15
-#define PT_SS  16
-
-static unsigned int
-getreg (struct task_struct *child, int regno)
-{
-       struct pt_regs *child_regs;
-
-       child_regs = task_pt_regs(child);
-       switch (regno / sizeof(int)) {
-             case PT_EBX: return child_regs->r11;
-             case PT_ECX: return child_regs->r9;
-             case PT_EDX: return child_regs->r10;
-             case PT_ESI: return child_regs->r14;
-             case PT_EDI: return child_regs->r15;
-             case PT_EBP: return child_regs->r13;
-             case PT_EAX: return child_regs->r8;
-             case PT_ORIG_EAX: return child_regs->r1; /* see dispatch_to_ia32_handler() */
-             case PT_EIP: return child_regs->cr_iip;
-             case PT_UESP: return child_regs->r12;
-             case PT_EFL: return child->thread.eflag;
-             case PT_DS: case PT_ES: case PT_FS: case PT_GS: case PT_SS:
-               return __USER_DS;
-             case PT_CS: return __USER_CS;
-             default:
-               printk(KERN_ERR "ia32.getreg(): unknown register %d\n", regno);
-               break;
-       }
-       return 0;
-}
-
-static void
-putreg (struct task_struct *child, int regno, unsigned int value)
-{
-       struct pt_regs *child_regs;
-
-       child_regs = task_pt_regs(child);
-       switch (regno / sizeof(int)) {
-             case PT_EBX: child_regs->r11 = value; break;
-             case PT_ECX: child_regs->r9 = value; break;
-             case PT_EDX: child_regs->r10 = value; break;
-             case PT_ESI: child_regs->r14 = value; break;
-             case PT_EDI: child_regs->r15 = value; break;
-             case PT_EBP: child_regs->r13 = value; break;
-             case PT_EAX: child_regs->r8 = value; break;
-             case PT_ORIG_EAX: child_regs->r1 = value; break;
-             case PT_EIP: child_regs->cr_iip = value; break;
-             case PT_UESP: child_regs->r12 = value; break;
-             case PT_EFL: child->thread.eflag = value; break;
-             case PT_DS: case PT_ES: case PT_FS: case PT_GS: case PT_SS:
-               if (value != __USER_DS)
-                       printk(KERN_ERR
-                              "ia32.putreg: attempt to set invalid segment register %d = %x\n",
-                              regno, value);
-               break;
-             case PT_CS:
-               if (value != __USER_CS)
-                       printk(KERN_ERR
-                              "ia32.putreg: attempt to set invalid segment register %d = %x\n",
-                              regno, value);
-               break;
-             default:
-               printk(KERN_ERR "ia32.putreg: unknown register %d\n", regno);
-               break;
-       }
-}
-
-static void
-put_fpreg (int regno, struct _fpreg_ia32 __user *reg, struct pt_regs *ptp,
-          struct switch_stack *swp, int tos)
-{
-       struct _fpreg_ia32 *f;
-       char buf[32];
-
-       f = (struct _fpreg_ia32 *)(((unsigned long)buf + 15) & ~15);
-       if ((regno += tos) >= 8)
-               regno -= 8;
-       switch (regno) {
-             case 0:
-               ia64f2ia32f(f, &ptp->f8);
-               break;
-             case 1:
-               ia64f2ia32f(f, &ptp->f9);
-               break;
-             case 2:
-               ia64f2ia32f(f, &ptp->f10);
-               break;
-             case 3:
-               ia64f2ia32f(f, &ptp->f11);
-               break;
-             case 4:
-             case 5:
-             case 6:
-             case 7:
-               ia64f2ia32f(f, &swp->f12 + (regno - 4));
-               break;
-       }
-       copy_to_user(reg, f, sizeof(*reg));
-}
-
-static void
-get_fpreg (int regno, struct _fpreg_ia32 __user *reg, struct pt_regs *ptp,
-          struct switch_stack *swp, int tos)
-{
-
-       if ((regno += tos) >= 8)
-               regno -= 8;
-       switch (regno) {
-             case 0:
-               copy_from_user(&ptp->f8, reg, sizeof(*reg));
-               break;
-             case 1:
-               copy_from_user(&ptp->f9, reg, sizeof(*reg));
-               break;
-             case 2:
-               copy_from_user(&ptp->f10, reg, sizeof(*reg));
-               break;
-             case 3:
-               copy_from_user(&ptp->f11, reg, sizeof(*reg));
-               break;
-             case 4:
-             case 5:
-             case 6:
-             case 7:
-               copy_from_user(&swp->f12 + (regno - 4), reg, sizeof(*reg));
-               break;
-       }
-       return;
-}
-
-int
-save_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct __user *save)
-{
-       struct switch_stack *swp;
-       struct pt_regs *ptp;
-       int i, tos;
-
-       if (!access_ok(VERIFY_WRITE, save, sizeof(*save)))
-               return -EFAULT;
-
-       __put_user(tsk->thread.fcr & 0xffff, &save->cwd);
-       __put_user(tsk->thread.fsr & 0xffff, &save->swd);
-       __put_user((tsk->thread.fsr>>16) & 0xffff, &save->twd);
-       __put_user(tsk->thread.fir, &save->fip);
-       __put_user((tsk->thread.fir>>32) & 0xffff, &save->fcs);
-       __put_user(tsk->thread.fdr, &save->foo);
-       __put_user((tsk->thread.fdr>>32) & 0xffff, &save->fos);
-
-       /*
-        *  Stack frames start with 16-bytes of temp space
-        */
-       swp = (struct switch_stack *)(tsk->thread.ksp + 16);
-       ptp = task_pt_regs(tsk);
-       tos = (tsk->thread.fsr >> 11) & 7;
-       for (i = 0; i < 8; i++)
-               put_fpreg(i, &save->st_space[i], ptp, swp, tos);
-       return 0;
-}
-
-static int
-restore_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct __user *save)
-{
-       struct switch_stack *swp;
-       struct pt_regs *ptp;
-       int i, tos;
-       unsigned int fsrlo, fsrhi, num32;
-
-       if (!access_ok(VERIFY_READ, save, sizeof(*save)))
-               return(-EFAULT);
-
-       __get_user(num32, (unsigned int __user *)&save->cwd);
-       tsk->thread.fcr = (tsk->thread.fcr & (~0x1f3f)) | (num32 & 0x1f3f);
-       __get_user(fsrlo, (unsigned int __user *)&save->swd);
-       __get_user(fsrhi, (unsigned int __user *)&save->twd);
-       num32 = (fsrhi << 16) | fsrlo;
-       tsk->thread.fsr = (tsk->thread.fsr & (~0xffffffff)) | num32;
-       __get_user(num32, (unsigned int __user *)&save->fip);
-       tsk->thread.fir = (tsk->thread.fir & (~0xffffffff)) | num32;
-       __get_user(num32, (unsigned int __user *)&save->foo);
-       tsk->thread.fdr = (tsk->thread.fdr & (~0xffffffff)) | num32;
-
-       /*
-        *  Stack frames start with 16-bytes of temp space
-        */
-       swp = (struct switch_stack *)(tsk->thread.ksp + 16);
-       ptp = task_pt_regs(tsk);
-       tos = (tsk->thread.fsr >> 11) & 7;
-       for (i = 0; i < 8; i++)
-               get_fpreg(i, &save->st_space[i], ptp, swp, tos);
-       return 0;
-}
-
-int
-save_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct __user *save)
-{
-       struct switch_stack *swp;
-       struct pt_regs *ptp;
-       int i, tos;
-       unsigned long mxcsr=0;
-       unsigned long num128[2];
-
-       if (!access_ok(VERIFY_WRITE, save, sizeof(*save)))
-               return -EFAULT;
-
-       __put_user(tsk->thread.fcr & 0xffff, &save->cwd);
-       __put_user(tsk->thread.fsr & 0xffff, &save->swd);
-       __put_user((tsk->thread.fsr>>16) & 0xffff, &save->twd);
-       __put_user(tsk->thread.fir, &save->fip);
-       __put_user((tsk->thread.fir>>32) & 0xffff, &save->fcs);
-       __put_user(tsk->thread.fdr, &save->foo);
-       __put_user((tsk->thread.fdr>>32) & 0xffff, &save->fos);
-
-        /*
-         *  Stack frames start with 16-bytes of temp space
-         */
-        swp = (struct switch_stack *)(tsk->thread.ksp + 16);
-        ptp = task_pt_regs(tsk);
-       tos = (tsk->thread.fsr >> 11) & 7;
-        for (i = 0; i < 8; i++)
-               put_fpreg(i, (struct _fpreg_ia32 __user *)&save->st_space[4*i], ptp, swp, tos);
-
-       mxcsr = ((tsk->thread.fcr>>32) & 0xff80) | ((tsk->thread.fsr>>32) & 0x3f);
-       __put_user(mxcsr & 0xffff, &save->mxcsr);
-       for (i = 0; i < 8; i++) {
-               memcpy(&(num128[0]), &(swp->f16) + i*2, sizeof(unsigned long));
-               memcpy(&(num128[1]), &(swp->f17) + i*2, sizeof(unsigned long));
-               copy_to_user(&save->xmm_space[0] + 4*i, num128, sizeof(struct _xmmreg_ia32));
-       }
-       return 0;
-}
-
-static int
-restore_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct __user *save)
-{
-       struct switch_stack *swp;
-       struct pt_regs *ptp;
-       int i, tos;
-       unsigned int fsrlo, fsrhi, num32;
-       int mxcsr;
-       unsigned long num64;
-       unsigned long num128[2];
-
-       if (!access_ok(VERIFY_READ, save, sizeof(*save)))
-               return(-EFAULT);
-
-       __get_user(num32, (unsigned int __user *)&save->cwd);
-       tsk->thread.fcr = (tsk->thread.fcr & (~0x1f3f)) | (num32 & 0x1f3f);
-       __get_user(fsrlo, (unsigned int __user *)&save->swd);
-       __get_user(fsrhi, (unsigned int __user *)&save->twd);
-       num32 = (fsrhi << 16) | fsrlo;
-       tsk->thread.fsr = (tsk->thread.fsr & (~0xffffffff)) | num32;
-       __get_user(num32, (unsigned int __user *)&save->fip);
-       tsk->thread.fir = (tsk->thread.fir & (~0xffffffff)) | num32;
-       __get_user(num32, (unsigned int __user *)&save->foo);
-       tsk->thread.fdr = (tsk->thread.fdr & (~0xffffffff)) | num32;
-
-       /*
-        *  Stack frames start with 16-bytes of temp space
-        */
-       swp = (struct switch_stack *)(tsk->thread.ksp + 16);
-       ptp = task_pt_regs(tsk);
-       tos = (tsk->thread.fsr >> 11) & 7;
-       for (i = 0; i < 8; i++)
-       get_fpreg(i, (struct _fpreg_ia32 __user *)&save->st_space[4*i], ptp, swp, tos);
-
-       __get_user(mxcsr, (unsigned int __user *)&save->mxcsr);
-       num64 = mxcsr & 0xff10;
-       tsk->thread.fcr = (tsk->thread.fcr & (~0xff1000000000UL)) | (num64<<32);
-       num64 = mxcsr & 0x3f;
-       tsk->thread.fsr = (tsk->thread.fsr & (~0x3f00000000UL)) | (num64<<32);
-
-       for (i = 0; i < 8; i++) {
-               copy_from_user(num128, &save->xmm_space[0] + 4*i, sizeof(struct _xmmreg_ia32));
-               memcpy(&(swp->f16) + i*2, &(num128[0]), sizeof(unsigned long));
-               memcpy(&(swp->f17) + i*2, &(num128[1]), sizeof(unsigned long));
-       }
-       return 0;
-}
-
-long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
-       compat_ulong_t caddr, compat_ulong_t cdata)
-{
-       unsigned long addr = caddr;
-       unsigned long data = cdata;
-       unsigned int tmp;
-       long i, ret;
-
-       switch (request) {
-             case PTRACE_PEEKUSR:      /* read word at addr in USER area */
-               ret = -EIO;
-               if ((addr & 3) || addr > 17*sizeof(int))
-                       break;
-
-               tmp = getreg(child, addr);
-               if (!put_user(tmp, (unsigned int __user *) compat_ptr(data)))
-                       ret = 0;
-               break;
-
-             case PTRACE_POKEUSR:      /* write word at addr in USER area */
-               ret = -EIO;
-               if ((addr & 3) || addr > 17*sizeof(int))
-                       break;
-
-               putreg(child, addr, data);
-               ret = 0;
-               break;
-
-             case IA32_PTRACE_GETREGS:
-               if (!access_ok(VERIFY_WRITE, compat_ptr(data), 17*sizeof(int))) {
-                       ret = -EIO;
-                       break;
-               }
-               for (i = 0; i < (int) (17*sizeof(int)); i += sizeof(int) ) {
-                       put_user(getreg(child, i), (unsigned int __user *) compat_ptr(data));
-                       data += sizeof(int);
-               }
-               ret = 0;
-               break;
-
-             case IA32_PTRACE_SETREGS:
-               if (!access_ok(VERIFY_READ, compat_ptr(data), 17*sizeof(int))) {
-                       ret = -EIO;
-                       break;
-               }
-               for (i = 0; i < (int) (17*sizeof(int)); i += sizeof(int) ) {
-                       get_user(tmp, (unsigned int __user *) compat_ptr(data));
-                       putreg(child, i, tmp);
-                       data += sizeof(int);
-               }
-               ret = 0;
-               break;
-
-             case IA32_PTRACE_GETFPREGS:
-               ret = save_ia32_fpstate(child, (struct ia32_user_i387_struct __user *)
-                                       compat_ptr(data));
-               break;
-
-             case IA32_PTRACE_GETFPXREGS:
-               ret = save_ia32_fpxstate(child, (struct ia32_user_fxsr_struct __user *)
-                                        compat_ptr(data));
-               break;
-
-             case IA32_PTRACE_SETFPREGS:
-               ret = restore_ia32_fpstate(child, (struct ia32_user_i387_struct __user *)
-                                          compat_ptr(data));
-               break;
-
-             case IA32_PTRACE_SETFPXREGS:
-               ret = restore_ia32_fpxstate(child, (struct ia32_user_fxsr_struct __user *)
-                                           compat_ptr(data));
-               break;
-
-             default:
-               return compat_ptrace_request(child, request, caddr, cdata);
-       }
-       return ret;
-}
-
-typedef struct {
-       unsigned int    ss_sp;
-       unsigned int    ss_flags;
-       unsigned int    ss_size;
-} ia32_stack_t;
-
-asmlinkage long
-sys32_sigaltstack (ia32_stack_t __user *uss32, ia32_stack_t __user *uoss32,
-                  long arg2, long arg3, long arg4, long arg5, long arg6,
-                  long arg7, struct pt_regs pt)
-{
-       stack_t uss, uoss;
-       ia32_stack_t buf32;
-       int ret;
-       mm_segment_t old_fs = get_fs();
-
-       if (uss32) {
-               if (copy_from_user(&buf32, uss32, sizeof(ia32_stack_t)))
-                       return -EFAULT;
-               uss.ss_sp = (void __user *) (long) buf32.ss_sp;
-               uss.ss_flags = buf32.ss_flags;
-               /* MINSIGSTKSZ is different for ia32 vs ia64. We lie here to pass the
-                  check and set it to the user requested value later */
-               if ((buf32.ss_flags != SS_DISABLE) && (buf32.ss_size < MINSIGSTKSZ_IA32)) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-               uss.ss_size = MINSIGSTKSZ;
-       }
-       set_fs(KERNEL_DS);
-       ret = do_sigaltstack(uss32 ? (stack_t __user *) &uss : NULL,
-                            (stack_t __user *) &uoss, pt.r12);
-       current->sas_ss_size = buf32.ss_size;
-       set_fs(old_fs);
-out:
-       if (ret < 0)
-               return(ret);
-       if (uoss32) {
-               buf32.ss_sp = (long __user) uoss.ss_sp;
-               buf32.ss_flags = uoss.ss_flags;
-               buf32.ss_size = uoss.ss_size;
-               if (copy_to_user(uoss32, &buf32, sizeof(ia32_stack_t)))
-                       return -EFAULT;
-       }
-       return ret;
-}
-
-asmlinkage int
-sys32_msync (unsigned int start, unsigned int len, int flags)
-{
-       unsigned int addr;
-
-       if (OFFSET4K(start))
-               return -EINVAL;
-       addr = PAGE_START(start);
-       return sys_msync(addr, len + (start - addr), flags);
-}
-
-asmlinkage long
-sys32_newuname (struct new_utsname __user *name)
-{
-       int ret = sys_newuname(name);
-
-       if (!ret)
-               if (copy_to_user(name->machine, "i686\0\0\0", 8))
-                       ret = -EFAULT;
-       return ret;
-}
-
-asmlinkage long
-sys32_getresuid16 (u16 __user *ruid, u16 __user *euid, u16 __user *suid)
-{
-       uid_t a, b, c;
-       int ret;
-       mm_segment_t old_fs = get_fs();
-
-       set_fs(KERNEL_DS);
-       ret = sys_getresuid((uid_t __user *) &a, (uid_t __user *) &b, (uid_t __user *) &c);
-       set_fs(old_fs);
-
-       if (put_user(a, ruid) || put_user(b, euid) || put_user(c, suid))
-               return -EFAULT;
-       return ret;
-}
-
-asmlinkage long
-sys32_getresgid16 (u16 __user *rgid, u16 __user *egid, u16 __user *sgid)
-{
-       gid_t a, b, c;
-       int ret;
-       mm_segment_t old_fs = get_fs();
-
-       set_fs(KERNEL_DS);
-       ret = sys_getresgid((gid_t __user *) &a, (gid_t __user *) &b, (gid_t __user *) &c);
-       set_fs(old_fs);
-
-       if (ret)
-               return ret;
-
-       return put_user(a, rgid) | put_user(b, egid) | put_user(c, sgid);
-}
-
-asmlinkage long
-sys32_lseek (unsigned int fd, int offset, unsigned int whence)
-{
-       /* Sign-extension of "offset" is important here... */
-       return sys_lseek(fd, offset, whence);
-}
-
-static int
-groups16_to_user(short __user *grouplist, struct group_info *group_info)
-{
-       int i;
-       short group;
-
-       for (i = 0; i < group_info->ngroups; i++) {
-               group = (short)GROUP_AT(group_info, i);
-               if (put_user(group, grouplist+i))
-                       return -EFAULT;
-       }
-
-       return 0;
-}
-
-static int
-groups16_from_user(struct group_info *group_info, short __user *grouplist)
-{
-       int i;
-       short group;
-
-       for (i = 0; i < group_info->ngroups; i++) {
-               if (get_user(group, grouplist+i))
-                       return  -EFAULT;
-               GROUP_AT(group_info, i) = (gid_t)group;
-       }
-
-       return 0;
-}
-
-asmlinkage long
-sys32_getgroups16 (int gidsetsize, short __user *grouplist)
-{
-       const struct cred *cred = current_cred();
-       int i;
-
-       if (gidsetsize < 0)
-               return -EINVAL;
-
-       i = cred->group_info->ngroups;
-       if (gidsetsize) {
-               if (i > gidsetsize) {
-                       i = -EINVAL;
-                       goto out;
-               }
-               if (groups16_to_user(grouplist, cred->group_info)) {
-                       i = -EFAULT;
-                       goto out;
-               }
-       }
-out:
-       return i;
-}
-
-asmlinkage long
-sys32_setgroups16 (int gidsetsize, short __user *grouplist)
-{
-       struct group_info *group_info;
-       int retval;
-
-       if (!capable(CAP_SETGID))
-               return -EPERM;
-       if ((unsigned)gidsetsize > NGROUPS_MAX)
-               return -EINVAL;
-
-       group_info = groups_alloc(gidsetsize);
-       if (!group_info)
-               return -ENOMEM;
-       retval = groups16_from_user(group_info, grouplist);
-       if (retval) {
-               put_group_info(group_info);
-               return retval;
-       }
-
-       retval = set_current_groups(group_info);
-       put_group_info(group_info);
-
-       return retval;
-}
-
-asmlinkage long
-sys32_truncate64 (unsigned int path, unsigned int len_lo, unsigned int len_hi)
-{
-       return sys_truncate(compat_ptr(path), ((unsigned long) len_hi << 32) | len_lo);
-}
-
-asmlinkage long
-sys32_ftruncate64 (int fd, unsigned int len_lo, unsigned int len_hi)
-{
-       return sys_ftruncate(fd, ((unsigned long) len_hi << 32) | len_lo);
-}
-
-static int
-putstat64 (struct stat64 __user *ubuf, struct kstat *kbuf)
-{
-       int err;
-       u64 hdev;
-
-       if (clear_user(ubuf, sizeof(*ubuf)))
-               return -EFAULT;
-
-       hdev = huge_encode_dev(kbuf->dev);
-       err  = __put_user(hdev, (u32 __user*)&ubuf->st_dev);
-       err |= __put_user(hdev >> 32, ((u32 __user*)&ubuf->st_dev) + 1);
-       err |= __put_user(kbuf->ino, &ubuf->__st_ino);
-       err |= __put_user(kbuf->ino, &ubuf->st_ino_lo);
-       err |= __put_user(kbuf->ino >> 32, &ubuf->st_ino_hi);
-       err |= __put_user(kbuf->mode, &ubuf->st_mode);
-       err |= __put_user(kbuf->nlink, &ubuf->st_nlink);
-       err |= __put_user(kbuf->uid, &ubuf->st_uid);
-       err |= __put_user(kbuf->gid, &ubuf->st_gid);
-       hdev = huge_encode_dev(kbuf->rdev);
-       err  = __put_user(hdev, (u32 __user*)&ubuf->st_rdev);
-       err |= __put_user(hdev >> 32, ((u32 __user*)&ubuf->st_rdev) + 1);
-       err |= __put_user(kbuf->size, &ubuf->st_size_lo);
-       err |= __put_user((kbuf->size >> 32), &ubuf->st_size_hi);
-       err |= __put_user(kbuf->atime.tv_sec, &ubuf->st_atime);
-       err |= __put_user(kbuf->atime.tv_nsec, &ubuf->st_atime_nsec);
-       err |= __put_user(kbuf->mtime.tv_sec, &ubuf->st_mtime);
-       err |= __put_user(kbuf->mtime.tv_nsec, &ubuf->st_mtime_nsec);
-       err |= __put_user(kbuf->ctime.tv_sec, &ubuf->st_ctime);
-       err |= __put_user(kbuf->ctime.tv_nsec, &ubuf->st_ctime_nsec);
-       err |= __put_user(kbuf->blksize, &ubuf->st_blksize);
-       err |= __put_user(kbuf->blocks, &ubuf->st_blocks);
-       return err;
-}
-
-asmlinkage long
-sys32_stat64 (char __user *filename, struct stat64 __user *statbuf)
-{
-       struct kstat s;
-       long ret = vfs_stat(filename, &s);
-       if (!ret)
-               ret = putstat64(statbuf, &s);
-       return ret;
-}
-
-asmlinkage long
-sys32_lstat64 (char __user *filename, struct stat64 __user *statbuf)
-{
-       struct kstat s;
-       long ret = vfs_lstat(filename, &s);
-       if (!ret)
-               ret = putstat64(statbuf, &s);
-       return ret;
-}
-
-asmlinkage long
-sys32_fstat64 (unsigned int fd, struct stat64 __user *statbuf)
-{
-       struct kstat s;
-       long ret = vfs_fstat(fd, &s);
-       if (!ret)
-               ret = putstat64(statbuf, &s);
-       return ret;
-}
-
-asmlinkage long
-sys32_sched_rr_get_interval (pid_t pid, struct compat_timespec __user *interval)
-{
-       mm_segment_t old_fs = get_fs();
-       struct timespec t;
-       long ret;
-
-       set_fs(KERNEL_DS);
-       ret = sys_sched_rr_get_interval(pid, (struct timespec __user *) &t);
-       set_fs(old_fs);
-       if (put_compat_timespec(&t, interval))
-               return -EFAULT;
-       return ret;
-}
-
-asmlinkage long
-sys32_pread (unsigned int fd, void __user *buf, unsigned int count, u32 pos_lo, u32 pos_hi)
-{
-       return sys_pread64(fd, buf, count, ((unsigned long) pos_hi << 32) | pos_lo);
-}
-
-asmlinkage long
-sys32_pwrite (unsigned int fd, void __user *buf, unsigned int count, u32 pos_lo, u32 pos_hi)
-{
-       return sys_pwrite64(fd, buf, count, ((unsigned long) pos_hi << 32) | pos_lo);
-}
-
-asmlinkage long
-sys32_sendfile (int out_fd, int in_fd, int __user *offset, unsigned int count)
-{
-       mm_segment_t old_fs = get_fs();
-       long ret;
-       off_t of;
-
-       if (offset && get_user(of, offset))
-               return -EFAULT;
-
-       set_fs(KERNEL_DS);
-       ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *) &of : NULL, count);
-       set_fs(old_fs);
-
-       if (offset && put_user(of, offset))
-               return -EFAULT;
-
-       return ret;
-}
-
-asmlinkage long
-sys32_personality (unsigned int personality)
-{
-       long ret;
-
-       if (current->personality == PER_LINUX32 && personality == PER_LINUX)
-               personality = PER_LINUX32;
-       ret = sys_personality(personality);
-       if (ret == PER_LINUX32)
-               ret = PER_LINUX;
-       return ret;
-}
-
-asmlinkage unsigned long
-sys32_brk (unsigned int brk)
-{
-       unsigned long ret, obrk;
-       struct mm_struct *mm = current->mm;
-
-       obrk = mm->brk;
-       ret = sys_brk(brk);
-       if (ret < obrk)
-               clear_user(compat_ptr(ret), PAGE_ALIGN(ret) - ret);
-       return ret;
-}
-
-/* Structure for ia32 emulation on ia64 */
-struct epoll_event32
-{
-       u32 events;
-       u32 data[2];
-};
-
-asmlinkage long
-sys32_epoll_ctl(int epfd, int op, int fd, struct epoll_event32 __user *event)
-{
-       mm_segment_t old_fs = get_fs();
-       struct epoll_event event64;
-       int error;
-       u32 data_halfword;
-
-       if (!access_ok(VERIFY_READ, event, sizeof(struct epoll_event32)))
-               return -EFAULT;
-
-       __get_user(event64.events, &event->events);
-       __get_user(data_halfword, &event->data[0]);
-       event64.data = data_halfword;
-       __get_user(data_halfword, &event->data[1]);
-       event64.data |= (u64)data_halfword << 32;
-
-       set_fs(KERNEL_DS);
-       error = sys_epoll_ctl(epfd, op, fd, (struct epoll_event __user *) &event64);
-       set_fs(old_fs);
-
-       return error;
-}
-
-asmlinkage long
-sys32_epoll_wait(int epfd, struct epoll_event32 __user * events, int maxevents,
-                int timeout)
-{
-       struct epoll_event *events64 = NULL;
-       mm_segment_t old_fs = get_fs();
-       int numevents, size;
-       int evt_idx;
-       int do_free_pages = 0;
-
-       if (maxevents <= 0) {
-               return -EINVAL;
-       }
-
-       /* Verify that the area passed by the user is writeable */
-       if (!access_ok(VERIFY_WRITE, events, maxevents * sizeof(struct epoll_event32)))
-               return -EFAULT;
-
-       /*
-        * Allocate space for the intermediate copy.  If the space needed
-        * is large enough to cause kmalloc to fail, then try again with
-        * __get_free_pages.
-        */
-       size = maxevents * sizeof(struct epoll_event);
-       events64 = kmalloc(size, GFP_KERNEL);
-       if (events64 == NULL) {
-               events64 = (struct epoll_event *)
-                               __get_free_pages(GFP_KERNEL, get_order(size));
-               if (events64 == NULL)
-                       return -ENOMEM;
-               do_free_pages = 1;
-       }
-
-       /* Do the system call */
-       set_fs(KERNEL_DS); /* copy_to/from_user should work on kernel mem*/
-       numevents = sys_epoll_wait(epfd, (struct epoll_event __user *) events64,
-                                  maxevents, timeout);
-       set_fs(old_fs);
-
-       /* Don't modify userspace memory if we're returning an error */
-       if (numevents > 0) {
-               /* Translate the 64-bit structures back into the 32-bit
-                  structures */
-               for (evt_idx = 0; evt_idx < numevents; evt_idx++) {
-                       __put_user(events64[evt_idx].events,
-                                  &events[evt_idx].events);
-                       __put_user((u32)events64[evt_idx].data,
-                                  &events[evt_idx].data[0]);
-                       __put_user((u32)(events64[evt_idx].data >> 32),
-                                  &events[evt_idx].data[1]);
-               }
-       }
-
-       if (do_free_pages)
-               free_pages((unsigned long) events64, get_order(size));
-       else
-               kfree(events64);
-       return numevents;
-}
-
-/*
- * Get a yet unused TLS descriptor index.
- */
-static int
-get_free_idx (void)
-{
-       struct thread_struct *t = &current->thread;
-       int idx;
-
-       for (idx = 0; idx < GDT_ENTRY_TLS_ENTRIES; idx++)
-               if (desc_empty(t->tls_array + idx))
-                       return idx + GDT_ENTRY_TLS_MIN;
-       return -ESRCH;
-}
-
-static void set_tls_desc(struct task_struct *p, int idx,
-               const struct ia32_user_desc *info, int n)
-{
-       struct thread_struct *t = &p->thread;
-       struct desc_struct *desc = &t->tls_array[idx - GDT_ENTRY_TLS_MIN];
-       int cpu;
-
-       /*
-        * We must not get preempted while modifying the TLS.
-        */
-       cpu = get_cpu();
-
-       while (n-- > 0) {
-               if (LDT_empty(info)) {
-                       desc->a = 0;
-                       desc->b = 0;
-               } else {
-                       desc->a = LDT_entry_a(info);
-                       desc->b = LDT_entry_b(info);
-               }
-
-               ++info;
-               ++desc;
-       }
-
-       if (t == &current->thread)
-               load_TLS(t, cpu);
-
-       put_cpu();
-}
-
-/*
- * Set a given TLS descriptor:
- */
-asmlinkage int
-sys32_set_thread_area (struct ia32_user_desc __user *u_info)
-{
-       struct ia32_user_desc info;
-       int idx;
-
-       if (copy_from_user(&info, u_info, sizeof(info)))
-               return -EFAULT;
-       idx = info.entry_number;
-
-       /*
-        * index -1 means the kernel should try to find and allocate an empty descriptor:
-        */
-       if (idx == -1) {
-               idx = get_free_idx();
-               if (idx < 0)
-                       return idx;
-               if (put_user(idx, &u_info->entry_number))
-                       return -EFAULT;
-       }
-
-       if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
-               return -EINVAL;
-
-       set_tls_desc(current, idx, &info, 1);
-       return 0;
-}
-
-/*
- * Get the current Thread-Local Storage area:
- */
-
-#define GET_BASE(desc) (                       \
-       (((desc)->a >> 16) & 0x0000ffff) |      \
-       (((desc)->b << 16) & 0x00ff0000) |      \
-       ( (desc)->b        & 0xff000000)   )
-
-#define GET_LIMIT(desc) (                      \
-       ((desc)->a & 0x0ffff) |                 \
-        ((desc)->b & 0xf0000) )
-
-#define GET_32BIT(desc)                (((desc)->b >> 22) & 1)
-#define GET_CONTENTS(desc)     (((desc)->b >> 10) & 3)
-#define GET_WRITABLE(desc)     (((desc)->b >>  9) & 1)
-#define GET_LIMIT_PAGES(desc)  (((desc)->b >> 23) & 1)
-#define GET_PRESENT(desc)      (((desc)->b >> 15) & 1)
-#define GET_USEABLE(desc)      (((desc)->b >> 20) & 1)
-
-static void fill_user_desc(struct ia32_user_desc *info, int idx,
-               const struct desc_struct *desc)
-{
-       info->entry_number = idx;
-       info->base_addr = GET_BASE(desc);
-       info->limit = GET_LIMIT(desc);
-       info->seg_32bit = GET_32BIT(desc);
-       info->contents = GET_CONTENTS(desc);
-       info->read_exec_only = !GET_WRITABLE(desc);
-       info->limit_in_pages = GET_LIMIT_PAGES(desc);
-       info->seg_not_present = !GET_PRESENT(desc);
-       info->useable = GET_USEABLE(desc);
-}
-
-asmlinkage int
-sys32_get_thread_area (struct ia32_user_desc __user *u_info)
-{
-       struct ia32_user_desc info;
-       struct desc_struct *desc;
-       int idx;
-
-       if (get_user(idx, &u_info->entry_number))
-               return -EFAULT;
-       if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
-               return -EINVAL;
-
-       desc = current->thread.tls_array + idx - GDT_ENTRY_TLS_MIN;
-       fill_user_desc(&info, idx, desc);
-
-       if (copy_to_user(u_info, &info, sizeof(info)))
-               return -EFAULT;
-       return 0;
-}
-
-struct regset_get {
-       void *kbuf;
-       void __user *ubuf;
-};
-
-struct regset_set {
-       const void *kbuf;
-       const void __user *ubuf;
-};
-
-struct regset_getset {
-       struct task_struct *target;
-       const struct user_regset *regset;
-       union {
-               struct regset_get get;
-               struct regset_set set;
-       } u;
-       unsigned int pos;
-       unsigned int count;
-       int ret;
-};
-
-static void getfpreg(struct task_struct *task, int regno, int *val)
-{
-       switch (regno / sizeof(int)) {
-       case 0:
-               *val = task->thread.fcr & 0xffff;
-               break;
-       case 1:
-               *val = task->thread.fsr & 0xffff;
-               break;
-       case 2:
-               *val = (task->thread.fsr>>16) & 0xffff;
-               break;
-       case 3:
-               *val = task->thread.fir;
-               break;
-       case 4:
-               *val = (task->thread.fir>>32) & 0xffff;
-               break;
-       case 5:
-               *val = task->thread.fdr;
-               break;
-       case 6:
-               *val = (task->thread.fdr >> 32) & 0xffff;
-               break;
-       }
-}
-
-static void setfpreg(struct task_struct *task, int regno, int val)
-{
-       switch (regno / sizeof(int)) {
-       case 0:
-               task->thread.fcr = (task->thread.fcr & (~0x1f3f))
-                       | (val & 0x1f3f);
-               break;
-       case 1:
-               task->thread.fsr = (task->thread.fsr & (~0xffff)) | val;
-               break;
-       case 2:
-               task->thread.fsr = (task->thread.fsr & (~0xffff0000))
-                       | (val << 16);
-               break;
-       case 3:
-               task->thread.fir = (task->thread.fir & (~0xffffffff)) | val;
-               break;
-       case 5:
-               task->thread.fdr = (task->thread.fdr & (~0xffffffff)) | val;
-               break;
-       }
-}
-
-static void access_fpreg_ia32(int regno, void *reg,
-               struct pt_regs *pt, struct switch_stack *sw,
-               int tos, int write)
-{
-       void *f;
-
-       if ((regno += tos) >= 8)
-               regno -= 8;
-       if (regno < 4)
-               f = &pt->f8 + regno;
-       else if (regno <= 7)
-               f = &sw->f12 + (regno - 4);
-       else {
-               printk(KERN_ERR "regno must be less than 7 \n");
-                return;
-       }
-
-       if (write)
-               memcpy(f, reg, sizeof(struct _fpreg_ia32));
-       else
-               memcpy(reg, f, sizeof(struct _fpreg_ia32));
-}
-
-static void do_fpregs_get(struct unw_frame_info *info, void *arg)
-{
-       struct regset_getset *dst = arg;
-       struct task_struct *task = dst->target;
-       struct pt_regs *pt;
-       int start, end, tos;
-       char buf[80];
-
-       if (dst->count == 0 || unw_unwind_to_user(info) < 0)
-               return;
-       if (dst->pos < 7 * sizeof(int)) {
-               end = min((dst->pos + dst->count),
-                       (unsigned int)(7 * sizeof(int)));
-               for (start = dst->pos; start < end; start += sizeof(int))
-                       getfpreg(task, start, (int *)(buf + start));
-               dst->ret = user_regset_copyout(&dst->pos, &dst->count,
-                               &dst->u.get.kbuf, &dst->u.get.ubuf, buf,
-                               0, 7 * sizeof(int));
-               if (dst->ret || dst->count == 0)
-                       return;
-       }
-       if (dst->pos < sizeof(struct ia32_user_i387_struct)) {
-               pt = task_pt_regs(task);
-               tos = (task->thread.fsr >> 11) & 7;
-               end = min(dst->pos + dst->count,
-                       (unsigned int)(sizeof(struct ia32_user_i387_struct)));
-               start = (dst->pos - 7 * sizeof(int)) /
-                       sizeof(struct _fpreg_ia32);
-               end = (end - 7 * sizeof(int)) / sizeof(struct _fpreg_ia32);
-               for (; start < end; start++)
-                       access_fpreg_ia32(start,
-                               (struct _fpreg_ia32 *)buf + start,
-                               pt, info->sw, tos, 0);
-               dst->ret = user_regset_copyout(&dst->pos, &dst->count,
-                               &dst->u.get.kbuf, &dst->u.get.ubuf,
-                               buf, 7 * sizeof(int),
-                               sizeof(struct ia32_user_i387_struct));
-               if (dst->ret || dst->count == 0)
-                       return;
-       }
-}
-
-static void do_fpregs_set(struct unw_frame_info *info, void *arg)
-{
-       struct regset_getset *dst = arg;
-       struct task_struct *task = dst->target;
-       struct pt_regs *pt;
-       char buf[80];
-       int end, start, tos;
-
-       if (dst->count == 0 || unw_unwind_to_user(info) < 0)
-               return;
-
-       if (dst->pos < 7 * sizeof(int)) {
-               start = dst->pos;
-               dst->ret = user_regset_copyin(&dst->pos, &dst->count,
-                               &dst->u.set.kbuf, &dst->u.set.ubuf, buf,
-                               0, 7 * sizeof(int));
-               if (dst->ret)
-                       return;
-               for (; start < dst->pos; start += sizeof(int))
-                       setfpreg(task, start, *((int *)(buf + start)));
-               if (dst->count == 0)
-                       return;
-       }
-       if (dst->pos < sizeof(struct ia32_user_i387_struct)) {
-               start = (dst->pos - 7 * sizeof(int)) /
-                       sizeof(struct _fpreg_ia32);
-               dst->ret = user_regset_copyin(&dst->pos, &dst->count,
-                               &dst->u.set.kbuf, &dst->u.set.ubuf,
-                               buf, 7 * sizeof(int),
-                               sizeof(struct ia32_user_i387_struct));
-               if (dst->ret)
-                       return;
-               pt = task_pt_regs(task);
-               tos = (task->thread.fsr >> 11) & 7;
-               end = (dst->pos - 7 * sizeof(int)) / sizeof(struct _fpreg_ia32);
-               for (; start < end; start++)
-                       access_fpreg_ia32(start,
-                               (struct _fpreg_ia32 *)buf + start,
-                               pt, info->sw, tos, 1);
-               if (dst->count == 0)
-                       return;
-       }
-}
-
-#define OFFSET(member) ((int)(offsetof(struct ia32_user_fxsr_struct, member)))
-static void getfpxreg(struct task_struct *task, int start, int end, char *buf)
-{
-       int min_val;
-
-       min_val = min(end, OFFSET(fop));
-       while (start < min_val) {
-               if (start == OFFSET(cwd))
-                       *((short *)buf) = task->thread.fcr & 0xffff;
-               else if (start == OFFSET(swd))
-                       *((short *)buf) = task->thread.fsr & 0xffff;
-               else if (start == OFFSET(twd))
-                       *((short *)buf) = (task->thread.fsr>>16) & 0xffff;
-               buf += 2;
-               start += 2;
-       }
-       /* skip fop element */
-       if (start == OFFSET(fop)) {
-               start += 2;
-               buf += 2;
-       }
-       while (start < end) {
-               if (start == OFFSET(fip))
-                       *((int *)buf) = task->thread.fir;
-               else if (start == OFFSET(fcs))
-                       *((int *)buf) = (task->thread.fir>>32) & 0xffff;
-               else if (start == OFFSET(foo))
-                       *((int *)buf) = task->thread.fdr;
-               else if (start == OFFSET(fos))
-                       *((int *)buf) = (task->thread.fdr>>32) & 0xffff;
-               else if (start == OFFSET(mxcsr))
-                       *((int *)buf) = ((task->thread.fcr>>32) & 0xff80)
-                                        | ((task->thread.fsr>>32) & 0x3f);
-               buf += 4;
-               start += 4;
-       }
-}
-
-static void setfpxreg(struct task_struct *task, int start, int end, char *buf)
-{
-       int min_val, num32;
-       short num;
-       unsigned long num64;
-
-       min_val = min(end, OFFSET(fop));
-       while (start < min_val) {
-               num = *((short *)buf);
-               if (start == OFFSET(cwd)) {
-                       task->thread.fcr = (task->thread.fcr & (~0x1f3f))
-                                               | (num & 0x1f3f);
-               } else if (start == OFFSET(swd)) {
-                       task->thread.fsr = (task->thread.fsr & (~0xffff)) | num;
-               } else if (start == OFFSET(twd)) {
-                       task->thread.fsr = (task->thread.fsr & (~0xffff0000))
-                               | (((int)num) << 16);
-               }
-               buf += 2;
-               start += 2;
-       }
-       /* skip fop element */
-       if (start == OFFSET(fop)) {
-               start += 2;
-               buf += 2;
-       }
-       while (start < end) {
-               num32 = *((int *)buf);
-               if (start == OFFSET(fip))
-                       task->thread.fir = (task->thread.fir & (~0xffffffff))
-                                                | num32;
-               else if (start == OFFSET(foo))
-                       task->thread.fdr = (task->thread.fdr & (~0xffffffff))
-                                                | num32;
-               else if (start == OFFSET(mxcsr)) {
-                       num64 = num32 & 0xff10;
-                       task->thread.fcr = (task->thread.fcr &
-                               (~0xff1000000000UL)) | (num64<<32);
-                       num64 = num32 & 0x3f;
-                       task->thread.fsr = (task->thread.fsr &
-                               (~0x3f00000000UL)) | (num64<<32);
-               }
-               buf += 4;
-               start += 4;
-       }
-}
-
-static void do_fpxregs_get(struct unw_frame_info *info, void *arg)
-{
-       struct regset_getset *dst = arg;
-       struct task_struct *task = dst->target;
-       struct pt_regs *pt;
-       char buf[128];
-       int start, end, tos;
-
-       if (dst->count == 0 || unw_unwind_to_user(info) < 0)
-               return;
-       if (dst->pos < OFFSET(st_space[0])) {
-               end = min(dst->pos + dst->count, (unsigned int)32);
-               getfpxreg(task, dst->pos, end, buf);
-               dst->ret = user_regset_copyout(&dst->pos, &dst->count,
-                               &dst->u.get.kbuf, &dst->u.get.ubuf, buf,
-                               0, OFFSET(st_space[0]));
-               if (dst->ret || dst->count == 0)
-                       return;
-       }
-       if (dst->pos < OFFSET(xmm_space[0])) {
-               pt = task_pt_regs(task);
-               tos = (task->thread.fsr >> 11) & 7;
-               end = min(dst->pos + dst->count,
-                               (unsigned int)OFFSET(xmm_space[0]));
-               start = (dst->pos - OFFSET(st_space[0])) / 16;
-               end = (end - OFFSET(st_space[0])) / 16;
-               for (; start < end; start++)
-                       access_fpreg_ia32(start, buf + 16 * start, pt,
-                                               info->sw, tos, 0);
-               dst->ret = user_regset_copyout(&dst->pos, &dst->count,
-                               &dst->u.get.kbuf, &dst->u.get.ubuf,
-                               buf, OFFSET(st_space[0]), OFFSET(xmm_space[0]));
-               if (dst->ret || dst->count == 0)
-                       return;
-       }
-       if (dst->pos < OFFSET(padding[0]))
-               dst->ret = user_regset_copyout(&dst->pos, &dst->count,
-                               &dst->u.get.kbuf, &dst->u.get.ubuf,
-                               &info->sw->f16, OFFSET(xmm_space[0]),
-                               OFFSET(padding[0]));
-}
-
-static void do_fpxregs_set(struct unw_frame_info *info, void *arg)
-{
-       struct regset_getset *dst = arg;
-       struct task_struct *task = dst->target;
-       char buf[128];
-       int start, end;
-
-       if (dst->count == 0 || unw_unwind_to_user(info) < 0)
-               return;
-
-       if (dst->pos < OFFSET(st_space[0])) {
-               start = dst->pos;
-               dst->ret = user_regset_copyin(&dst->pos, &dst->count,
-                               &dst->u.set.kbuf, &dst->u.set.ubuf,
-                               buf, 0, OFFSET(st_space[0]));
-               if (dst->ret)
-                       return;
-               setfpxreg(task, start, dst->pos, buf);
-               if (dst->count == 0)
-                       return;
-       }
-       if (dst->pos < OFFSET(xmm_space[0])) {
-               struct pt_regs *pt;
-               int tos;
-               pt = task_pt_regs(task);
-               tos = (task->thread.fsr >> 11) & 7;
-               start = (dst->pos - OFFSET(st_space[0])) / 16;
-               dst->ret = user_regset_copyin(&dst->pos, &dst->count,
-                               &dst->u.set.kbuf, &dst->u.set.ubuf,
-                               buf, OFFSET(st_space[0]), OFFSET(xmm_space[0]));
-               if (dst->ret)
-                       return;
-               end = (dst->pos - OFFSET(st_space[0])) / 16;
-               for (; start < end; start++)
-                       access_fpreg_ia32(start, buf + 16 * start, pt, info->sw,
-                                                tos, 1);
-               if (dst->count == 0)
-                       return;
-       }
-       if (dst->pos < OFFSET(padding[0]))
-               dst->ret = user_regset_copyin(&dst->pos, &dst->count,
-                               &dst->u.set.kbuf, &dst->u.set.ubuf,
-                               &info->sw->f16, OFFSET(xmm_space[0]),
-                                OFFSET(padding[0]));
-}
-#undef OFFSET
-
-static int do_regset_call(void (*call)(struct unw_frame_info *, void *),
-               struct task_struct *target,
-               const struct user_regset *regset,
-               unsigned int pos, unsigned int count,
-               const void *kbuf, const void __user *ubuf)
-{
-       struct regset_getset info = { .target = target, .regset = regset,
-               .pos = pos, .count = count,
-               .u.set = { .kbuf = kbuf, .ubuf = ubuf },
-               .ret = 0 };
-
-       if (target == current)
-               unw_init_running(call, &info);
-       else {
-               struct unw_frame_info ufi;
-               memset(&ufi, 0, sizeof(ufi));
-               unw_init_from_blocked_task(&ufi, target);
-               (*call)(&ufi, &info);
-       }
-
-       return info.ret;
-}
-
-static int ia32_fpregs_get(struct task_struct *target,
-               const struct user_regset *regset,
-               unsigned int pos, unsigned int count,
-               void *kbuf, void __user *ubuf)
-{
-       return do_regset_call(do_fpregs_get, target, regset, pos, count,
-               kbuf, ubuf);
-}
-
-static int ia32_fpregs_set(struct task_struct *target,
-               const struct user_regset *regset,
-               unsigned int pos, unsigned int count,
-               const void *kbuf, const void __user *ubuf)
-{
-       return do_regset_call(do_fpregs_set, target, regset, pos, count,
-               kbuf, ubuf);
-}
-
-static int ia32_fpxregs_get(struct task_struct *target,
-               const struct user_regset *regset,
-               unsigned int pos, unsigned int count,
-               void *kbuf, void __user *ubuf)
-{
-       return do_regset_call(do_fpxregs_get, target, regset, pos, count,
-               kbuf, ubuf);
-}
-
-static int ia32_fpxregs_set(struct task_struct *target,
-               const struct user_regset *regset,
-               unsigned int pos, unsigned int count,
-               const void *kbuf, const void __user *ubuf)
-{
-       return do_regset_call(do_fpxregs_set, target, regset, pos, count,
-               kbuf, ubuf);
-}
-
-static int ia32_genregs_get(struct task_struct *target,
-               const struct user_regset *regset,
-               unsigned int pos, unsigned int count,
-               void *kbuf, void __user *ubuf)
-{
-       if (kbuf) {
-               u32 *kp = kbuf;
-               while (count > 0) {
-                       *kp++ = getreg(target, pos);
-                       pos += 4;
-                       count -= 4;
-               }
-       } else {
-               u32 __user *up = ubuf;
-               while (count > 0) {
-                       if (__put_user(getreg(target, pos), up++))
-                               return -EFAULT;
-                       pos += 4;
-                       count -= 4;
-               }
-       }
-       return 0;
-}
-
-static int ia32_genregs_set(struct task_struct *target,
-               const struct user_regset *regset,
-               unsigned int pos, unsigned int count,
-               const void *kbuf, const void __user *ubuf)
-{
-       int ret = 0;
-
-       if (kbuf) {
-               const u32 *kp = kbuf;
-               while (!ret && count > 0) {
-                       putreg(target, pos, *kp++);
-                       pos += 4;
-                       count -= 4;
-               }
-       } else {
-               const u32 __user *up = ubuf;
-               u32 val;
-               while (!ret && count > 0) {
-                       ret = __get_user(val, up++);
-                       if (!ret)
-                               putreg(target, pos, val);
-                       pos += 4;
-                       count -= 4;
-               }
-       }
-       return ret;
-}
-
-static int ia32_tls_active(struct task_struct *target,
-               const struct user_regset *regset)
-{
-       struct thread_struct *t = &target->thread;
-       int n = GDT_ENTRY_TLS_ENTRIES;
-       while (n > 0 && desc_empty(&t->tls_array[n -1]))
-               --n;
-       return n;
-}
-
-static int ia32_tls_get(struct task_struct *target,
-               const struct user_regset *regset, unsigned int pos,
-               unsigned int count, void *kbuf, void __user *ubuf)
-{
-       const struct desc_struct *tls;
-
-       if (pos > GDT_ENTRY_TLS_ENTRIES * sizeof(struct ia32_user_desc) ||
-                       (pos % sizeof(struct ia32_user_desc)) != 0 ||
-                       (count % sizeof(struct ia32_user_desc)) != 0)
-               return -EINVAL;
-
-       pos /= sizeof(struct ia32_user_desc);
-       count /= sizeof(struct ia32_user_desc);
-
-       tls = &target->thread.tls_array[pos];
-
-       if (kbuf) {
-               struct ia32_user_desc *info = kbuf;
-               while (count-- > 0)
-                       fill_user_desc(info++, GDT_ENTRY_TLS_MIN + pos++,
-                                       tls++);
-       } else {
-               struct ia32_user_desc __user *u_info = ubuf;
-               while (count-- > 0) {
-                       struct ia32_user_desc info;
-                       fill_user_desc(&info, GDT_ENTRY_TLS_MIN + pos++, tls++);
-                       if (__copy_to_user(u_info++, &info, sizeof(info)))
-                               return -EFAULT;
-               }
-       }
-
-       return 0;
-}
-
-static int ia32_tls_set(struct task_struct *target,
-               const struct user_regset *regset, unsigned int pos,
-               unsigned int count, const void *kbuf, const void __user *ubuf)
-{
-       struct ia32_user_desc infobuf[GDT_ENTRY_TLS_ENTRIES];
-       const struct ia32_user_desc *info;
-
-       if (pos > GDT_ENTRY_TLS_ENTRIES * sizeof(struct ia32_user_desc) ||
-                       (pos % sizeof(struct ia32_user_desc)) != 0 ||
-                       (count % sizeof(struct ia32_user_desc)) != 0)
-               return -EINVAL;
-
-       if (kbuf)
-               info = kbuf;
-       else if (__copy_from_user(infobuf, ubuf, count))
-               return -EFAULT;
-       else
-               info = infobuf;
-
-       set_tls_desc(target,
-               GDT_ENTRY_TLS_MIN + (pos / sizeof(struct ia32_user_desc)),
-               info, count / sizeof(struct ia32_user_desc));
-
-       return 0;
-}
-
-/*
- * This should match arch/i386/kernel/ptrace.c:native_regsets.
- * XXX ioperm? vm86?
- */
-static const struct user_regset ia32_regsets[] = {
-       {
-               .core_note_type = NT_PRSTATUS,
-               .n = sizeof(struct user_regs_struct32)/4,
-               .size = 4, .align = 4,
-               .get = ia32_genregs_get, .set = ia32_genregs_set
-       },
-       {
-               .core_note_type = NT_PRFPREG,
-               .n = sizeof(struct ia32_user_i387_struct) / 4,
-               .size = 4, .align = 4,
-               .get = ia32_fpregs_get, .set = ia32_fpregs_set
-       },
-       {
-               .core_note_type = NT_PRXFPREG,
-               .n = sizeof(struct ia32_user_fxsr_struct) / 4,
-               .size = 4, .align = 4,
-               .get = ia32_fpxregs_get, .set = ia32_fpxregs_set
-       },
-       {
-               .core_note_type = NT_386_TLS,
-               .n = GDT_ENTRY_TLS_ENTRIES,
-               .bias = GDT_ENTRY_TLS_MIN,
-               .size = sizeof(struct ia32_user_desc),
-               .align = sizeof(struct ia32_user_desc),
-               .active = ia32_tls_active,
-               .get = ia32_tls_get, .set = ia32_tls_set,
-       },
-};
-
-const struct user_regset_view user_ia32_view = {
-       .name = "i386", .e_machine = EM_386,
-       .regsets = ia32_regsets, .n = ARRAY_SIZE(ia32_regsets)
-};
-
-long sys32_fadvise64_64(int fd, __u32 offset_low, __u32 offset_high, 
-                       __u32 len_low, __u32 len_high, int advice)
-{ 
-       return sys_fadvise64_64(fd,
-                              (((u64)offset_high)<<32) | offset_low,
-                              (((u64)len_high)<<32) | len_low,
-                              advice); 
-} 
-
-#ifdef NOTYET  /* UNTESTED FOR IA64 FROM HERE DOWN */
-
-asmlinkage long sys32_setreuid(compat_uid_t ruid, compat_uid_t euid)
-{
-       uid_t sruid, seuid;
-
-       sruid = (ruid == (compat_uid_t)-1) ? ((uid_t)-1) : ((uid_t)ruid);
-       seuid = (euid == (compat_uid_t)-1) ? ((uid_t)-1) : ((uid_t)euid);
-       return sys_setreuid(sruid, seuid);
-}
-
-asmlinkage long
-sys32_setresuid(compat_uid_t ruid, compat_uid_t euid,
-               compat_uid_t suid)
-{
-       uid_t sruid, seuid, ssuid;
-
-       sruid = (ruid == (compat_uid_t)-1) ? ((uid_t)-1) : ((uid_t)ruid);
-       seuid = (euid == (compat_uid_t)-1) ? ((uid_t)-1) : ((uid_t)euid);
-       ssuid = (suid == (compat_uid_t)-1) ? ((uid_t)-1) : ((uid_t)suid);
-       return sys_setresuid(sruid, seuid, ssuid);
-}
-
-asmlinkage long
-sys32_setregid(compat_gid_t rgid, compat_gid_t egid)
-{
-       gid_t srgid, segid;
-
-       srgid = (rgid == (compat_gid_t)-1) ? ((gid_t)-1) : ((gid_t)rgid);
-       segid = (egid == (compat_gid_t)-1) ? ((gid_t)-1) : ((gid_t)egid);
-       return sys_setregid(srgid, segid);
-}
-
-asmlinkage long
-sys32_setresgid(compat_gid_t rgid, compat_gid_t egid,
-               compat_gid_t sgid)
-{
-       gid_t srgid, segid, ssgid;
-
-       srgid = (rgid == (compat_gid_t)-1) ? ((gid_t)-1) : ((gid_t)rgid);
-       segid = (egid == (compat_gid_t)-1) ? ((gid_t)-1) : ((gid_t)egid);
-       ssgid = (sgid == (compat_gid_t)-1) ? ((gid_t)-1) : ((gid_t)sgid);
-       return sys_setresgid(srgid, segid, ssgid);
-}
-#endif /* NOTYET */
index 93997bd5edc3031bf724c6f54fcb53fc98c8feb3..21adbd7f90f86cf588e10638e1cf93091f2b5388 100644 (file)
@@ -100,7 +100,32 @@ ia64_acpi_release_global_lock (unsigned int *lock)
 static inline void disable_acpi(void) { }
 static inline void pci_acpi_crs_quirks(void) { }
 
+#ifdef CONFIG_IA64_GENERIC
 const char *acpi_get_sysname (void);
+#else
+static inline const char *acpi_get_sysname (void)
+{
+# if defined (CONFIG_IA64_HP_SIM)
+       return "hpsim";
+# elif defined (CONFIG_IA64_HP_ZX1)
+       return "hpzx1";
+# elif defined (CONFIG_IA64_HP_ZX1_SWIOTLB)
+       return "hpzx1_swiotlb";
+# elif defined (CONFIG_IA64_SGI_SN2)
+       return "sn2";
+# elif defined (CONFIG_IA64_SGI_UV)
+       return "uv";
+# elif defined (CONFIG_IA64_DIG)
+       return "dig";
+# elif defined (CONFIG_IA64_XEN_GUEST)
+       return "xen";
+# elif defined(CONFIG_IA64_DIG_VTD)
+       return "dig_vtd";
+# else
+#      error Unknown platform.  Fix acpi.c.
+# endif
+}
+#endif
 int acpi_request_vector (u32 int_type);
 int acpi_gsi_to_irq (u32 gsi, unsigned int *irq);
 
diff --git a/arch/ia64/include/asm/ia32.h b/arch/ia64/include/asm/ia32.h
deleted file mode 100644 (file)
index 2390ee1..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef _ASM_IA64_IA32_H
-#define _ASM_IA64_IA32_H
-
-
-#include <asm/ptrace.h>
-#include <asm/signal.h>
-
-#define IA32_NR_syscalls               285     /* length of syscall table */
-#define IA32_PAGE_SHIFT                        12      /* 4KB pages */
-
-#ifndef __ASSEMBLY__
-
-# ifdef CONFIG_IA32_SUPPORT
-
-#define IA32_PAGE_OFFSET       0xc0000000
-
-extern void ia32_cpu_init (void);
-extern void ia32_mem_init (void);
-extern void ia32_gdt_init (void);
-extern int ia32_exception (struct pt_regs *regs, unsigned long isr);
-extern int ia32_intercept (struct pt_regs *regs, unsigned long isr);
-extern int ia32_clone_tls (struct task_struct *child, struct pt_regs *childregs);
-
-# endif /* !CONFIG_IA32_SUPPORT */
-
-/* Declare this unconditionally, so we don't get warnings for unreachable code.  */
-extern int ia32_setup_frame1 (int sig, struct k_sigaction *ka, siginfo_t *info,
-                             sigset_t *set, struct pt_regs *regs);
-#if PAGE_SHIFT > IA32_PAGE_SHIFT
-extern int ia32_copy_ia64_partial_page_list(struct task_struct *,
-                                       unsigned long);
-extern void ia32_drop_ia64_partial_page_list(struct task_struct *);
-#else
-# define ia32_copy_ia64_partial_page_list(a1, a2)      0
-# define ia32_drop_ia64_partial_page_list(a1)  do { ; } while (0)
-#endif
-
-#endif /* !__ASSEMBLY__ */
-
-#endif /* _ASM_IA64_IA32_H */
index 69bf13857a9fc8ac9ff07e73a24436c17af19adb..c3286f42e501477722bdec7373112e92efc8a40d 100644 (file)
@@ -462,7 +462,7 @@ pte_same (pte_t a, pte_t b)
        return pte_val(a) == pte_val(b);
 }
 
-#define update_mmu_cache(vma, address, pte) do { } while (0)
+#define update_mmu_cache(vma, address, ptep) do { } while (0)
 
 extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
 extern void paging_init (void);
index 7fa90f73f6be37757e3a36ed46c85ac3ede3df77..348e44d08ce356adffbde1560ccbfddb5552c65f 100644 (file)
@@ -270,23 +270,6 @@ typedef struct {
                 (int __user *) (addr));                                                        \
 })
 
-#ifdef CONFIG_IA32_SUPPORT
-struct desc_struct {
-       unsigned int a, b;
-};
-
-#define desc_empty(desc)               (!((desc)->a | (desc)->b))
-#define desc_equal(desc1, desc2)       (((desc1)->a == (desc2)->a) && ((desc1)->b == (desc2)->b))
-
-#define GDT_ENTRY_TLS_ENTRIES  3
-#define GDT_ENTRY_TLS_MIN      6
-#define GDT_ENTRY_TLS_MAX      (GDT_ENTRY_TLS_MIN + GDT_ENTRY_TLS_ENTRIES - 1)
-
-#define TLS_SIZE (GDT_ENTRY_TLS_ENTRIES * 8)
-
-struct ia64_partial_page_list;
-#endif
-
 struct thread_struct {
        __u32 flags;                    /* various thread flags (see IA64_THREAD_*) */
        /* writing on_ustack is performance-critical, so it's worth spending 8 bits on it... */
@@ -298,29 +281,6 @@ struct thread_struct {
        __u64 rbs_bot;                  /* the base address for the RBS */
        int last_fph_cpu;               /* CPU that may hold the contents of f32-f127 */
 
-#ifdef CONFIG_IA32_SUPPORT
-       __u64 eflag;                    /* IA32 EFLAGS reg */
-       __u64 fsr;                      /* IA32 floating pt status reg */
-       __u64 fcr;                      /* IA32 floating pt control reg */
-       __u64 fir;                      /* IA32 fp except. instr. reg */
-       __u64 fdr;                      /* IA32 fp except. data reg */
-       __u64 old_k1;                   /* old value of ar.k1 */
-       __u64 old_iob;                  /* old IOBase value */
-       struct ia64_partial_page_list *ppl; /* partial page list for 4K page size issue */
-        /* cached TLS descriptors. */
-       struct desc_struct tls_array[GDT_ENTRY_TLS_ENTRIES];
-
-# define INIT_THREAD_IA32      .eflag =        0,                      \
-                               .fsr =          0,                      \
-                               .fcr =          0x17800000037fULL,      \
-                               .fir =          0,                      \
-                               .fdr =          0,                      \
-                               .old_k1 =       0,                      \
-                               .old_iob =      0,                      \
-                               .ppl =          NULL,
-#else
-# define INIT_THREAD_IA32
-#endif /* CONFIG_IA32_SUPPORT */
 #ifdef CONFIG_PERFMON
        void *pfm_context;                   /* pointer to detailed PMU context */
        unsigned long pfm_needs_checking;    /* when >0, pending perfmon work on kernel exit */
@@ -342,7 +302,6 @@ struct thread_struct {
        .rbs_bot =      STACK_TOP - DEFAULT_USER_STACK_SIZE,    \
        .task_size =    DEFAULT_TASK_SIZE,                      \
        .last_fph_cpu =  -1,                                    \
-       INIT_THREAD_IA32                                        \
        INIT_THREAD_PM                                          \
        .dbr =          {0, },                                  \
        .ibr =          {0, },                                  \
@@ -485,11 +444,6 @@ extern void __ia64_load_fpu (struct ia64_fpreg *fph);
 extern void ia64_save_debug_regs (unsigned long *save_area);
 extern void ia64_load_debug_regs (unsigned long *save_area);
 
-#ifdef CONFIG_IA32_SUPPORT
-extern void ia32_save_state (struct task_struct *task);
-extern void ia32_load_state (struct task_struct *task);
-#endif
-
 #define ia64_fph_enable()      do { ia64_rsm(IA64_PSR_DFH); ia64_srlz_d(); } while (0)
 #define ia64_fph_disable()     do { ia64_ssm(IA64_PSR_DFH); ia64_srlz_d(); } while (0)
 
index d6f57874041d0f80e351dcfeafb27aed21d755a8..d8e98961dec77e42be573f1778b6d69a542c21a2 100644 (file)
@@ -1,25 +1,6 @@
 #ifndef _ASM_IA64_SCATTERLIST_H
 #define _ASM_IA64_SCATTERLIST_H
 
-/*
- * Modified 1998-1999, 2001-2002, 2004
- *     David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co
- */
-
-#include <asm/types.h>
-
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-       unsigned long sg_magic;
-#endif
-       unsigned long page_link;
-       unsigned int offset;
-       unsigned int length;    /* buffer length */
-
-       dma_addr_t dma_address;
-       unsigned int dma_length;
-};
-
 /*
  * It used to be that ISA_DMA_THRESHOLD had something to do with the
  * DMA-limits of ISA-devices.  Nowadays, its only remaining use (apart
@@ -30,9 +11,6 @@ struct scatterlist {
  */
 #define ISA_DMA_THRESHOLD      0xffffffff
 
-#define sg_dma_len(sg)         ((sg)->dma_length)
-#define sg_dma_address(sg)     ((sg)->dma_address)
-
-#define        ARCH_HAS_SG_CHAIN
+#include <asm-generic/scatterlist.h>
 
 #endif /* _ASM_IA64_SCATTERLIST_H */
index 2f758a42f94bfaf086b9cc8361431c4ff9b683fe..a7ff1c6ab0689af9e547c5a138df286423b9788b 100644 (file)
@@ -22,33 +22,18 @@ static inline long syscall_get_nr(struct task_struct *task,
        if ((long)regs->cr_ifs < 0) /* Not a syscall */
                return -1;
 
-#ifdef CONFIG_IA32_SUPPORT
-       if (IS_IA32_PROCESS(regs))
-               return regs->r1;
-#endif
-
        return regs->r15;
 }
 
 static inline void syscall_rollback(struct task_struct *task,
                                    struct pt_regs *regs)
 {
-#ifdef CONFIG_IA32_SUPPORT
-       if (IS_IA32_PROCESS(regs))
-               regs->r8 = regs->r1;
-#endif
-
        /* do nothing */
 }
 
 static inline long syscall_get_error(struct task_struct *task,
                                     struct pt_regs *regs)
 {
-#ifdef CONFIG_IA32_SUPPORT
-       if (IS_IA32_PROCESS(regs))
-               return regs->r8;
-#endif
-
        return regs->r10 == -1 ? regs->r8:0;
 }
 
@@ -62,13 +47,6 @@ static inline void syscall_set_return_value(struct task_struct *task,
                                            struct pt_regs *regs,
                                            int error, long val)
 {
-#ifdef CONFIG_IA32_SUPPORT
-       if (IS_IA32_PROCESS(regs)) {
-               regs->r8 = (long) error ? error : val;
-               return;
-       }
-#endif
-
        if (error) {
                /* error < 0, but ia64 uses > 0 return value */
                regs->r8 = -error;
@@ -89,37 +67,6 @@ static inline void syscall_get_arguments(struct task_struct *task,
 {
        BUG_ON(i + n > 6);
 
-#ifdef CONFIG_IA32_SUPPORT
-       if (IS_IA32_PROCESS(regs)) {
-               switch (i + n) {
-               case 6:
-                       if (!n--) break;
-                       *args++ = regs->r13;
-               case 5:
-                       if (!n--) break;
-                       *args++ = regs->r15;
-               case 4:
-                       if (!n--) break;
-                       *args++ = regs->r14;
-               case 3:
-                       if (!n--) break;
-                       *args++ = regs->r10;
-               case 2:
-                       if (!n--) break;
-                       *args++ = regs->r9;
-               case 1:
-                       if (!n--) break;
-                       *args++ = regs->r11;
-               case 0:
-                       if (!n--) break;
-               default:
-                       BUG();
-                       break;
-               }
-
-               return;
-       }
-#endif
        ia64_syscall_get_set_arguments(task, regs, i, n, args, 0);
 }
 
@@ -130,34 +77,6 @@ static inline void syscall_set_arguments(struct task_struct *task,
 {
        BUG_ON(i + n > 6);
 
-#ifdef CONFIG_IA32_SUPPORT
-       if (IS_IA32_PROCESS(regs)) {
-               switch (i + n) {
-               case 6:
-                       if (!n--) break;
-                       regs->r13 = *args++;
-               case 5:
-                       if (!n--) break;
-                       regs->r15 = *args++;
-               case 4:
-                       if (!n--) break;
-                       regs->r14 = *args++;
-               case 3:
-                       if (!n--) break;
-                       regs->r10 = *args++;
-               case 2:
-                       if (!n--) break;
-                       regs->r9 = *args++;
-               case 1:
-                       if (!n--) break;
-                       regs->r11 = *args++;
-               case 0:
-                       if (!n--) break;
-               }
-
-               return;
-       }
-#endif
        ia64_syscall_get_set_arguments(task, regs, i, n, args, 1);
 }
 #endif /* _ASM_SYSCALL_H */
index 927a381c20ca06e35c7ba7ed10a6ef35e1826752..9f342a574ce8c669310b6857b5b1ac7152f8bae0 100644 (file)
@@ -191,15 +191,6 @@ do {                                                               \
 
 #ifdef __KERNEL__
 
-#ifdef CONFIG_IA32_SUPPORT
-# define IS_IA32_PROCESS(regs) (ia64_psr(regs)->is != 0)
-#else
-# define IS_IA32_PROCESS(regs)         0
-struct task_struct;
-static inline void ia32_save_state(struct task_struct *t __attribute__((unused))){}
-static inline void ia32_load_state(struct task_struct *t __attribute__((unused))){}
-#endif
-
 /*
  * Context switch from one thread to another.  If the two threads have
  * different address spaces, schedule() has already taken care of
@@ -233,7 +224,7 @@ extern void ia64_account_on_switch (struct task_struct *prev, struct task_struct
 
 #define IA64_HAS_EXTRA_STATE(t)                                                        \
        ((t)->thread.flags & (IA64_THREAD_DBG_VALID|IA64_THREAD_PM_VALID)       \
-        || IS_IA32_PROCESS(task_pt_regs(t)) || PERFMON_IS_SYSWIDE())
+        || PERFMON_IS_SYSWIDE())
 
 #define __switch_to(prev,next,last) do {                                                        \
        IA64_ACCOUNT_ON_SWITCH(prev, next);                                                      \
index 10a8f21ca9e3ffc4244765786167ae9acfb05aaa..bb8b0fff32b3f5c46f9d348f98ebe9a0b2f177ec 100644 (file)
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
 
-#ifdef CONFIG_IA32_SUPPORT
-# define __ARCH_WANT_SYS_FADVISE64
-# define __ARCH_WANT_SYS_GETPGRP
-# define __ARCH_WANT_SYS_LLSEEK
-# define __ARCH_WANT_SYS_NICE
-# define __ARCH_WANT_SYS_OLD_GETRLIMIT
-# define __ARCH_WANT_SYS_OLDUMOUNT
-# define __ARCH_WANT_SYS_PAUSE
-# define __ARCH_WANT_SYS_SIGPENDING
-# define __ARCH_WANT_SYS_SIGPROCMASK
-# define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
-# define __ARCH_WANT_COMPAT_SYS_TIME
-#endif
-
 #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER)
 
 #include <linux/types.h>
index e1236349c99fa3dd8ae7e0686425e77e9b4b0a30..4138282aefa86acb81a548464d10c0a3527e2508 100644 (file)
@@ -8,15 +8,13 @@ endif
 
 extra-y        := head.o init_task.o vmlinux.lds
 
-obj-y := acpi.o entry.o efi.o efi_stub.o gate-data.o fsys.o ia64_ksyms.o irq.o irq_ia64.o      \
+obj-y := entry.o efi.o efi_stub.o gate-data.o fsys.o ia64_ksyms.o irq.o irq_ia64.o     \
         irq_lsapic.o ivt.o machvec.o pal.o paravirt_patchlist.o patch.o process.o perfmon.o ptrace.o sal.o             \
         salinfo.o setup.o signal.o sys_ia64.o time.o traps.o unaligned.o \
         unwind.o mca.o mca_asm.o topology.o dma-mapping.o
 
+obj-$(CONFIG_ACPI)             += acpi.o acpi-ext.o
 obj-$(CONFIG_IA64_BRL_EMU)     += brl_emu.o
-obj-$(CONFIG_IA64_GENERIC)     += acpi-ext.o
-obj-$(CONFIG_IA64_HP_ZX1)      += acpi-ext.o
-obj-$(CONFIG_IA64_HP_ZX1_SWIOTLB) += acpi-ext.o
 
 obj-$(CONFIG_IA64_PALINFO)     += palinfo.o
 obj-$(CONFIG_IOSAPIC)          += iosapic.o
index 40574ae114018e4db5efce7fc499435c4c863eec..c16fb03037d4a2c69703465d135b44e5e173a6e5 100644 (file)
 
 #define PREFIX                 "ACPI: "
 
-void (*pm_idle) (void);
-EXPORT_SYMBOL(pm_idle);
-void (*pm_power_off) (void);
-EXPORT_SYMBOL(pm_power_off);
-
 u32 acpi_rsdt_forced;
 unsigned int acpi_cpei_override;
 unsigned int acpi_cpei_phys_cpuid;
@@ -83,12 +78,10 @@ static unsigned long __init acpi_find_rsdp(void)
                       "v1.0/r0.71 tables no longer supported\n");
        return rsdp_phys;
 }
-#endif
 
 const char __init *
 acpi_get_sysname(void)
 {
-#ifdef CONFIG_IA64_GENERIC
        unsigned long rsdp_phys;
        struct acpi_table_rsdp *rsdp;
        struct acpi_table_xsdt *xsdt;
@@ -143,30 +136,8 @@ acpi_get_sysname(void)
 #endif
 
        return "dig";
-#else
-# if defined (CONFIG_IA64_HP_SIM)
-       return "hpsim";
-# elif defined (CONFIG_IA64_HP_ZX1)
-       return "hpzx1";
-# elif defined (CONFIG_IA64_HP_ZX1_SWIOTLB)
-       return "hpzx1_swiotlb";
-# elif defined (CONFIG_IA64_SGI_SN2)
-       return "sn2";
-# elif defined (CONFIG_IA64_SGI_UV)
-       return "uv";
-# elif defined (CONFIG_IA64_DIG)
-       return "dig";
-# elif defined (CONFIG_IA64_XEN_GUEST)
-       return "xen";
-# elif defined(CONFIG_IA64_DIG_VTD)
-       return "dig_vtd";
-# else
-#      error Unknown platform.  Fix acpi.c.
-# endif
-#endif
 }
-
-#ifdef CONFIG_ACPI
+#endif /* CONFIG_IA64_GENERIC */
 
 #define ACPI_MAX_PLATFORM_INTERRUPTS   256
 
@@ -1060,5 +1031,3 @@ void acpi_restore_state_mem(void) {}
  * do_suspend_lowlevel()
  */
 void do_suspend_lowlevel(void) {}
-
-#endif                         /* CONFIG_ACPI */
index f3802ae89b108c610d16e3f0b6ab7b9597c21478..96a9d18ff4c4c87c0c469b9d3ecd7cbd3c6963ca 100644 (file)
@@ -30,20 +30,11 @@ static unsigned signal_class[] = {
 
 int audit_classify_arch(int arch)
 {
-#ifdef CONFIG_IA32_SUPPORT
-       if (arch == AUDIT_ARCH_I386)
-               return 1;
-#endif
        return 0;
 }
 
 int audit_classify_syscall(int abi, unsigned syscall)
 {
-#ifdef CONFIG_IA32_SUPPORT
-       extern int ia32_classify_syscall(unsigned);
-       if (abi == AUDIT_ARCH_I386)
-               return ia32_classify_syscall(syscall);
-#endif
        switch(syscall) {
        case __NR_open:
                return 2;
@@ -58,18 +49,6 @@ int audit_classify_syscall(int abi, unsigned syscall)
 
 static int __init audit_classes_init(void)
 {
-#ifdef CONFIG_IA32_SUPPORT
-       extern __u32 ia32_dir_class[];
-       extern __u32 ia32_write_class[];
-       extern __u32 ia32_read_class[];
-       extern __u32 ia32_chattr_class[];
-       extern __u32 ia32_signal_class[];
-       audit_register_class(AUDIT_CLASS_WRITE_32, ia32_write_class);
-       audit_register_class(AUDIT_CLASS_READ_32, ia32_read_class);
-       audit_register_class(AUDIT_CLASS_DIR_WRITE_32, ia32_dir_class);
-       audit_register_class(AUDIT_CLASS_CHATTR_32, ia32_chattr_class);
-       audit_register_class(AUDIT_CLASS_SIGNAL_32, ia32_signal_class);
-#endif
        audit_register_class(AUDIT_CLASS_WRITE, write_class);
        audit_register_class(AUDIT_CLASS_READ, read_class);
        audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class);
index d75b872ca4dc8cbe632d0b7d2a8659d9e07c1c8f..9a260b317d8d430b31c609ae03decb72fbd96a60 100644 (file)
@@ -71,15 +71,6 @@ ENTRY(ia64_execve)
        add out3=16,sp                  // regs
        br.call.sptk.many rp=sys_execve
 .ret0:
-#ifdef CONFIG_IA32_SUPPORT
-       /*
-        * Check if we're returning to ia32 mode. If so, we need to restore ia32 registers
-        * from pt_regs.
-        */
-       adds r16=PT(CR_IPSR)+16,sp
-       ;;
-       ld8 r16=[r16]
-#endif
        cmp4.ge p6,p7=r8,r0
        mov ar.pfs=loc1                 // restore ar.pfs
        sxt4 r8=r8                      // return 64-bit result
@@ -108,12 +99,6 @@ ENTRY(ia64_execve)
        ldf.fill f23=[sp];      ldf.fill f24=[sp];      mov f25=f0
        ldf.fill f26=[sp];      ldf.fill f27=[sp];      mov f28=f0
        ldf.fill f29=[sp];      ldf.fill f30=[sp];      mov f31=f0
-#ifdef CONFIG_IA32_SUPPORT
-       tbit.nz p6,p0=r16, IA64_PSR_IS_BIT
-       movl loc0=ia64_ret_from_ia32_execve
-       ;;
-(p6)   mov rp=loc0
-#endif
        br.ret.sptk.many rp
 END(ia64_execve)
 
@@ -848,30 +833,6 @@ __paravirt_work_processed_syscall:
        br.cond.sptk.many rbs_switch    // B
 END(__paravirt_leave_syscall)
 
-#ifdef __IA64_ASM_PARAVIRTUALIZED_NATIVE
-#ifdef CONFIG_IA32_SUPPORT
-GLOBAL_ENTRY(ia64_ret_from_ia32_execve)
-       PT_REGS_UNWIND_INFO(0)
-       adds r2=PT(R8)+16,sp                    // r2 = &pt_regs.r8
-       adds r3=PT(R10)+16,sp                   // r3 = &pt_regs.r10
-       ;;
-       .mem.offset 0,0
-       st8.spill [r2]=r8       // store return value in slot for r8 and set unat bit
-       .mem.offset 8,0
-       st8.spill [r3]=r0       // clear error indication in slot for r10 and set unat bit
-#ifdef CONFIG_PARAVIRT
-       ;;
-       // don't fall through, ia64_leave_kernel may be #define'd
-       br.cond.sptk.few ia64_leave_kernel
-       ;;
-#endif /* CONFIG_PARAVIRT */
-END(ia64_ret_from_ia32_execve)
-#ifndef CONFIG_PARAVIRT
-       // fall through
-#endif
-#endif /* CONFIG_IA32_SUPPORT */
-#endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */
-
 GLOBAL_ENTRY(__paravirt_leave_kernel)
        PT_REGS_UNWIND_INFO(0)
        /*
index ec9a5fdfa1b9dc6e899fe690503bc8a4604cf4db..179fd122e837dadf5bdc153e47aa288592e47ed6 100644 (file)
@@ -49,7 +49,6 @@
 
 #include <asm/asmmacro.h>
 #include <asm/break.h>
-#include <asm/ia32.h>
 #include <asm/kregs.h>
 #include <asm/asm-offsets.h>
 #include <asm/pgtable.h>
@@ -1386,28 +1385,6 @@ END(ia32_exception)
 // 0x6a00 Entry 46 (size 16 bundles) IA-32 Intercept  (30,31,59,70,71)
 ENTRY(ia32_intercept)
        DBG_FAULT(46)
-#ifdef CONFIG_IA32_SUPPORT
-       mov r31=pr
-       MOV_FROM_ISR(r16)
-       ;;
-       extr.u r17=r16,16,8     // get ISR.code
-       mov r18=ar.eflag
-       MOV_FROM_IIM(r19)       // old eflag value
-       ;;
-       cmp.ne p6,p0=2,r17
-(p6)   br.cond.spnt 1f         // not a system flag fault
-       xor r16=r18,r19
-       ;;
-       extr.u r17=r16,18,1     // get the eflags.ac bit
-       ;;
-       cmp.eq p6,p0=0,r17
-(p6)   br.cond.spnt 1f         // eflags.ac bit didn't change
-       ;;
-       mov pr=r31,-1           // restore predicate registers
-       RFI
-
-1:
-#endif // CONFIG_IA32_SUPPORT
        FAULT(46)
 END(ia32_intercept)
 
@@ -1416,12 +1393,7 @@ END(ia32_intercept)
 // 0x6b00 Entry 47 (size 16 bundles) IA-32 Interrupt  (74)
 ENTRY(ia32_interrupt)
        DBG_FAULT(47)
-#ifdef CONFIG_IA32_SUPPORT
-       mov r31=pr
-       br.sptk.many dispatch_to_ia32_handler
-#else
        FAULT(47)
-#endif
 END(ia32_interrupt)
 
        .org ia64_ivt+0x6c00
@@ -1715,89 +1687,3 @@ ENTRY(dispatch_illegal_op_fault)
 (p6)   br.call.dpnt.many b6=b6         // call returns to ia64_leave_kernel
        br.sptk.many ia64_leave_kernel
 END(dispatch_illegal_op_fault)
-
-#ifdef CONFIG_IA32_SUPPORT
-
-       /*
-        * There is no particular reason for this code to be here, other than that
-        * there happens to be space here that would go unused otherwise.  If this
-        * fault ever gets "unreserved", simply moved the following code to a more
-        * suitable spot...
-        */
-
-       // IA32 interrupt entry point
-
-ENTRY(dispatch_to_ia32_handler)
-       SAVE_MIN
-       ;;
-       MOV_FROM_ISR(r14)
-       SSM_PSR_IC_AND_DEFAULT_BITS_AND_SRLZ_I(r3, r24)
-                               // guarantee that interruption collection is on
-       ;;
-       SSM_PSR_I(p15, p15, r3)
-       adds r3=8,r2            // Base pointer for SAVE_REST
-       ;;
-       SAVE_REST
-       ;;
-       mov r15=0x80
-       shr r14=r14,16          // Get interrupt number
-       ;;
-       cmp.ne p6,p0=r14,r15
-(p6)   br.call.dpnt.many b6=non_ia32_syscall
-
-       adds r14=IA64_PT_REGS_R8_OFFSET + 16,sp // 16 byte hole per SW conventions
-       adds r15=IA64_PT_REGS_R1_OFFSET + 16,sp
-       ;;
-       cmp.eq pSys,pNonSys=r0,r0 // set pSys=1, pNonSys=0
-       ld8 r8=[r14]            // get r8
-       ;;
-       st8 [r15]=r8            // save original EAX in r1 (IA32 procs don't use the GP)
-       ;;
-       alloc r15=ar.pfs,0,0,6,0        // must first in an insn group
-       ;;
-       ld4 r8=[r14],8          // r8 == eax (syscall number)
-       mov r15=IA32_NR_syscalls
-       ;;
-       cmp.ltu.unc p6,p7=r8,r15
-       ld4 out1=[r14],8        // r9 == ecx
-       ;;
-       ld4 out2=[r14],8        // r10 == edx
-       ;;
-       ld4 out0=[r14]          // r11 == ebx
-       adds r14=(IA64_PT_REGS_R13_OFFSET) + 16,sp
-       ;;
-       ld4 out5=[r14],PT(R14)-PT(R13)  // r13 == ebp
-       ;;
-       ld4 out3=[r14],PT(R15)-PT(R14)  // r14 == esi
-       adds r2=TI_FLAGS+IA64_TASK_SIZE,r13
-       ;;
-       ld4 out4=[r14]          // r15 == edi
-       movl r16=ia32_syscall_table
-       ;;
-(p6)   shladd r16=r8,3,r16     // force ni_syscall if not valid syscall number
-       ld4 r2=[r2]             // r2 = current_thread_info()->flags
-       ;;
-       ld8 r16=[r16]
-       and r2=_TIF_SYSCALL_TRACEAUDIT,r2       // mask trace or audit
-       ;;
-       mov b6=r16
-       movl r15=ia32_ret_from_syscall
-       cmp.eq p8,p0=r2,r0
-       ;;
-       mov rp=r15
-(p8)   br.call.sptk.many b6=b6
-       br.cond.sptk ia32_trace_syscall
-
-non_ia32_syscall:
-       alloc r15=ar.pfs,0,0,2,0
-       mov out0=r14                            // interrupt #
-       add out1=16,sp                          // pointer to pt_regs
-       ;;                      // avoid WAW on CFM
-       br.call.sptk.many rp=ia32_bad_interrupt
-.ret1: movl r15=ia64_leave_kernel
-       ;;
-       mov rp=r15
-       br.ret.sptk.many rp
-END(dispatch_to_ia32_handler)
-
-#endif /* CONFIG_IA32_SUPPORT */
index 6bcbe215b9a418e555cad4793e20a6723d7b88f9..b81e46b1629b2a0cfe12e40eac2426c33b33a4e1 100644 (file)
@@ -2713,7 +2713,7 @@ pfm_context_create(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg
                        goto buffer_error;
        }
 
-       DPRINT(("ctx=%p flags=0x%x system=%d notify_block=%d excl_idle=%d no_msg=%d ctx_fd=%d \n",
+       DPRINT(("ctx=%p flags=0x%x system=%d notify_block=%d excl_idle=%d no_msg=%d ctx_fd=%d\n",
                ctx,
                ctx_flags,
                ctx->ctx_fl_system,
@@ -3677,7 +3677,7 @@ pfm_restart(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
         * "self-monitoring".
         */
        if (CTX_OVFL_NOBLOCK(ctx) == 0 && state == PFM_CTX_MASKED) {
-               DPRINT(("unblocking [%d] \n", task_pid_nr(task)));
+               DPRINT(("unblocking [%d]\n", task_pid_nr(task)));
                complete(&ctx->ctx_restart_done);
        } else {
                DPRINT(("[%d] armed exit trap\n", task_pid_nr(task)));
index 9bcec9945c1256417efa2829f6334922aaa7a5aa..d92765cae10a802d920eca6eaf634621b233a467 100644 (file)
@@ -33,7 +33,6 @@
 #include <asm/cpu.h>
 #include <asm/delay.h>
 #include <asm/elf.h>
-#include <asm/ia32.h>
 #include <asm/irq.h>
 #include <asm/kexec.h>
 #include <asm/pgalloc.h>
@@ -60,6 +59,10 @@ unsigned long idle_halt;
 EXPORT_SYMBOL(idle_halt);
 unsigned long idle_nomwait;
 EXPORT_SYMBOL(idle_nomwait);
+void (*pm_idle) (void);
+EXPORT_SYMBOL(pm_idle);
+void (*pm_power_off) (void);
+EXPORT_SYMBOL(pm_power_off);
 
 void
 ia64_do_show_stack (struct unw_frame_info *info, void *arg)
@@ -358,11 +361,6 @@ ia64_save_extra (struct task_struct *task)
        if (info & PFM_CPUINFO_SYST_WIDE)
                pfm_syst_wide_update_task(task, info, 0);
 #endif
-
-#ifdef CONFIG_IA32_SUPPORT
-       if (IS_IA32_PROCESS(task_pt_regs(task)))
-               ia32_save_state(task);
-#endif
 }
 
 void
@@ -383,11 +381,6 @@ ia64_load_extra (struct task_struct *task)
        if (info & PFM_CPUINFO_SYST_WIDE) 
                pfm_syst_wide_update_task(task, info, 1);
 #endif
-
-#ifdef CONFIG_IA32_SUPPORT
-       if (IS_IA32_PROCESS(task_pt_regs(task)))
-               ia32_load_state(task);
-#endif
 }
 
 /*
@@ -426,7 +419,7 @@ copy_thread(unsigned long clone_flags,
             unsigned long user_stack_base, unsigned long user_stack_size,
             struct task_struct *p, struct pt_regs *regs)
 {
-       extern char ia64_ret_from_clone, ia32_ret_from_clone;
+       extern char ia64_ret_from_clone;
        struct switch_stack *child_stack, *stack;
        unsigned long rbs, child_rbs, rbs_size;
        struct pt_regs *child_ptregs;
@@ -457,7 +450,7 @@ copy_thread(unsigned long clone_flags,
        memcpy((void *) child_rbs, (void *) rbs, rbs_size);
 
        if (likely(user_mode(child_ptregs))) {
-               if ((clone_flags & CLONE_SETTLS) && !IS_IA32_PROCESS(regs))
+               if (clone_flags & CLONE_SETTLS)
                        child_ptregs->r13 = regs->r16;  /* see sys_clone2() in entry.S */
                if (user_stack_base) {
                        child_ptregs->r12 = user_stack_base + user_stack_size - 16;
@@ -477,10 +470,7 @@ copy_thread(unsigned long clone_flags,
                child_ptregs->r13 = (unsigned long) p;          /* set `current' pointer */
        }
        child_stack->ar_bspstore = child_rbs + rbs_size;
-       if (IS_IA32_PROCESS(regs))
-               child_stack->b0 = (unsigned long) &ia32_ret_from_clone;
-       else
-               child_stack->b0 = (unsigned long) &ia64_ret_from_clone;
+       child_stack->b0 = (unsigned long) &ia64_ret_from_clone;
 
        /* copy parts of thread_struct: */
        p->thread.ksp = (unsigned long) child_stack - 16;
@@ -515,22 +505,6 @@ copy_thread(unsigned long clone_flags,
        p->thread.flags = ((current->thread.flags & ~THREAD_FLAGS_TO_CLEAR)
                           | THREAD_FLAGS_TO_SET);
        ia64_drop_fpu(p);       /* don't pick up stale state from a CPU's fph */
-#ifdef CONFIG_IA32_SUPPORT
-       /*
-        * If we're cloning an IA32 task then save the IA32 extra
-        * state from the current task to the new task
-        */
-       if (IS_IA32_PROCESS(task_pt_regs(current))) {
-               ia32_save_state(p);
-               if (clone_flags & CLONE_SETTLS)
-                       retval = ia32_clone_tls(p, child_ptregs);
-
-               /* Copy partially mapped page list */
-               if (!retval)
-                       retval = ia32_copy_ia64_partial_page_list(p,
-                                                               clone_flags);
-       }
-#endif
 
 #ifdef CONFIG_PERFMON
        if (current->thread.pfm_context)
@@ -704,15 +678,6 @@ EXPORT_SYMBOL(kernel_thread);
 int
 kernel_thread_helper (int (*fn)(void *), void *arg)
 {
-#ifdef CONFIG_IA32_SUPPORT
-       if (IS_IA32_PROCESS(task_pt_regs(current))) {
-               /* A kernel thread is always a 64-bit process. */
-               current->thread.map_base  = DEFAULT_MAP_BASE;
-               current->thread.task_size = DEFAULT_TASK_SIZE;
-               ia64_set_kr(IA64_KR_IO_BASE, current->thread.old_iob);
-               ia64_set_kr(IA64_KR_TSSD, current->thread.old_k1);
-       }
-#endif
        return (*fn)(arg);
 }
 
@@ -725,14 +690,6 @@ flush_thread (void)
        /* drop floating-point and debug-register state if it exists: */
        current->thread.flags &= ~(IA64_THREAD_FPH_VALID | IA64_THREAD_DBG_VALID);
        ia64_drop_fpu(current);
-#ifdef CONFIG_IA32_SUPPORT
-       if (IS_IA32_PROCESS(task_pt_regs(current))) {
-               ia32_drop_ia64_partial_page_list(current);
-               current->thread.task_size = IA32_PAGE_OFFSET;
-               set_fs(USER_DS);
-               memset(current->thread.tls_array, 0, sizeof(current->thread.tls_array));
-       }
-#endif
 }
 
 /*
@@ -753,8 +710,6 @@ exit_thread (void)
        if (current->thread.flags & IA64_THREAD_DBG_VALID)
                pfm_release_debug_registers(current);
 #endif
-       if (IS_IA32_PROCESS(task_pt_regs(current)))
-               ia32_drop_ia64_partial_page_list(current);
 }
 
 unsigned long
index 9daa87fdb0182e63cde61e6c78df1ff6dea41340..b61afbbe076f6152935e79fca3eb7da61f251c71 100644 (file)
@@ -1250,13 +1250,8 @@ syscall_trace_enter (long arg0, long arg1, long arg2, long arg3,
                long syscall;
                int arch;
 
-               if (IS_IA32_PROCESS(&regs)) {
-                       syscall = regs.r1;
-                       arch = AUDIT_ARCH_I386;
-               } else {
-                       syscall = regs.r15;
-                       arch = AUDIT_ARCH_IA64;
-               }
+               syscall = regs.r15;
+               arch = AUDIT_ARCH_IA64;
 
                audit_syscall_entry(arch, syscall, arg0, arg1, arg2, arg3);
        }
@@ -2172,11 +2167,6 @@ static const struct user_regset_view user_ia64_view = {
 
 const struct user_regset_view *task_user_regset_view(struct task_struct *tsk)
 {
-#ifdef CONFIG_IA32_SUPPORT
-       extern const struct user_regset_view user_ia32_view;
-       if (IS_IA32_PROCESS(task_pt_regs(tsk)))
-               return &user_ia32_view;
-#endif
        return &user_ia64_view;
 }
 
index a1ea879197770a2347ccff6ac0049146937d1ca9..41ae6a596b50a8cec1ff7146e547093779257c90 100644 (file)
@@ -46,7 +46,6 @@
 #include <linux/kexec.h>
 #include <linux/crash_dump.h>
 
-#include <asm/ia32.h>
 #include <asm/machvec.h>
 #include <asm/mca.h>
 #include <asm/meminit.h>
@@ -1016,10 +1015,6 @@ cpu_init (void)
        ia64_mmu_init(ia64_imva(cpu_data));
        ia64_mca_cpu_init(ia64_imva(cpu_data));
 
-#ifdef CONFIG_IA32_SUPPORT
-       ia32_cpu_init();
-#endif
-
        /* Clear ITC to eliminate sched_clock() overflows in human time.  */
        ia64_set_itc(0);
 
index e1821ca4c7dfddea3827102e2bd63a016e1162f3..7bdafc8788bd6e6cb25a6ea6b3a9120071c34adf 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/unistd.h>
 #include <linux/wait.h>
 
-#include <asm/ia32.h>
 #include <asm/intrinsics.h>
 #include <asm/uaccess.h>
 #include <asm/rse.h>
@@ -425,14 +424,8 @@ static long
 handle_signal (unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset,
               struct sigscratch *scr)
 {
-       if (IS_IA32_PROCESS(&scr->pt)) {
-               /* send signal to IA-32 process */
-               if (!ia32_setup_frame1(sig, ka, info, oldset, &scr->pt))
-                       return 0;
-       } else
-               /* send signal to IA-64 process */
-               if (!setup_frame(sig, ka, info, oldset, scr))
-                       return 0;
+       if (!setup_frame(sig, ka, info, oldset, scr))
+               return 0;
 
        spin_lock_irq(&current->sighand->siglock);
        sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
@@ -462,7 +455,6 @@ ia64_do_signal (struct sigscratch *scr, long in_syscall)
        siginfo_t info;
        long restart = in_syscall;
        long errno = scr->pt.r8;
-#      define ERR_CODE(c)      (IS_IA32_PROCESS(&scr->pt) ? -(c) : (c))
 
        /*
         * In the ia64_leave_kernel code path, we want the common case to go fast, which
@@ -490,14 +482,7 @@ ia64_do_signal (struct sigscratch *scr, long in_syscall)
                 * inferior call), thus it's important to check for restarting _after_
                 * get_signal_to_deliver().
                 */
-               if (IS_IA32_PROCESS(&scr->pt)) {
-                       if (in_syscall) {
-                               if (errno >= 0)
-                                       restart = 0;
-                               else
-                                       errno = -errno;
-                       }
-               } else if ((long) scr->pt.r10 != -1)
+               if ((long) scr->pt.r10 != -1)
                        /*
                         * A system calls has to be restarted only if one of the error codes
                         * ERESTARTNOHAND, ERESTARTSYS, or ERESTARTNOINTR is returned.  If r10
@@ -513,22 +498,18 @@ ia64_do_signal (struct sigscratch *scr, long in_syscall)
                        switch (errno) {
                              case ERESTART_RESTARTBLOCK:
                              case ERESTARTNOHAND:
-                               scr->pt.r8 = ERR_CODE(EINTR);
+                               scr->pt.r8 = EINTR;
                                /* note: scr->pt.r10 is already -1 */
                                break;
 
                              case ERESTARTSYS:
                                if ((ka.sa.sa_flags & SA_RESTART) == 0) {
-                                       scr->pt.r8 = ERR_CODE(EINTR);
+                                       scr->pt.r8 = EINTR;
                                        /* note: scr->pt.r10 is already -1 */
                                        break;
                                }
                              case ERESTARTNOINTR:
-                               if (IS_IA32_PROCESS(&scr->pt)) {
-                                       scr->pt.r8 = scr->pt.r1;
-                                       scr->pt.cr_iip -= 2;
-                               } else
-                                       ia64_decrement_ip(&scr->pt);
+                               ia64_decrement_ip(&scr->pt);
                                restart = 0; /* don't restart twice if handle_signal() fails... */
                        }
                }
@@ -555,21 +536,14 @@ ia64_do_signal (struct sigscratch *scr, long in_syscall)
                if (errno == ERESTARTNOHAND || errno == ERESTARTSYS || errno == ERESTARTNOINTR
                    || errno == ERESTART_RESTARTBLOCK)
                {
-                       if (IS_IA32_PROCESS(&scr->pt)) {
-                               scr->pt.r8 = scr->pt.r1;
-                               scr->pt.cr_iip -= 2;
-                               if (errno == ERESTART_RESTARTBLOCK)
-                                       scr->pt.r8 = 0; /* x86 version of __NR_restart_syscall */
-                       } else {
-                               /*
-                                * Note: the syscall number is in r15 which is saved in
-                                * pt_regs so all we need to do here is adjust ip so that
-                                * the "break" instruction gets re-executed.
-                                */
-                               ia64_decrement_ip(&scr->pt);
-                               if (errno == ERESTART_RESTARTBLOCK)
-                                       scr->pt.r15 = __NR_restart_syscall;
-                       }
+                       /*
+                        * Note: the syscall number is in r15 which is saved in
+                        * pt_regs so all we need to do here is adjust ip so that
+                        * the "break" instruction gets re-executed.
+                        */
+                       ia64_decrement_ip(&scr->pt);
+                       if (errno == ERESTART_RESTARTBLOCK)
+                               scr->pt.r15 = __NR_restart_syscall;
                }
        }
 
index de100aa7ff03dcc07127facacd59f05010d6d0b7..e5230b2ff2c5e4dbc7d74d84c4142d0634e92a63 100644 (file)
@@ -44,7 +44,6 @@
 #include <asm/cache.h>
 #include <asm/current.h>
 #include <asm/delay.h>
-#include <asm/ia32.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/machvec.h>
@@ -443,10 +442,6 @@ smp_callin (void)
                calibrate_delay();
        local_cpu_data->loops_per_jiffy = loops_per_jiffy;
 
-#ifdef CONFIG_IA32_SUPPORT
-       ia32_gdt_init();
-#endif
-
        /*
         * Allow the master to continue.
         */
index a35c661e5e89a544b097f731af1e65486c3077c2..47a192781b0aab9f3144170394a1564fb0b30cff 100644 (file)
@@ -61,7 +61,7 @@ unsigned long long sched_clock(void)
 
 #ifdef CONFIG_PARAVIRT
 static void
-paravirt_clocksource_resume(void)
+paravirt_clocksource_resume(struct clocksource *cs)
 {
        if (pv_time_ops.clocksource_resume)
                pv_time_ops.clocksource_resume();
index f0cda765e681d1252347675d45f582f8ab470b65..fd80e70018a959ebffdf860c962cf0ff062cc4f5 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/kdebug.h>
 
 #include <asm/fpswa.h>
-#include <asm/ia32.h>
 #include <asm/intrinsics.h>
 #include <asm/processor.h>
 #include <asm/uaccess.h>
@@ -626,10 +625,6 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
                break;
 
              case 45:
-#ifdef CONFIG_IA32_SUPPORT
-               if (ia32_exception(&regs, isr) == 0)
-                       return;
-#endif
                printk(KERN_ERR "Unexpected IA-32 exception (Trap 45)\n");
                printk(KERN_ERR "  iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx\n",
                       iip, ifa, isr);
@@ -637,10 +632,6 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
                break;
 
              case 46:
-#ifdef CONFIG_IA32_SUPPORT
-               if (ia32_intercept(&regs, isr) == 0)
-                       return;
-#endif
                printk(KERN_ERR "Unexpected IA-32 intercept trap (Trap 46)\n");
                printk(KERN_ERR "  iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx, iim - 0x%lx\n",
                       iip, ifa, isr, iim);
index 7c0d4814a68dc12a2f5f2dca9b16f1631a7f8314..ca3335ea56ccf9dae52d19ddbe619315f1134225 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/kexec.h>
 
 #include <asm/dma.h>
-#include <asm/ia32.h>
 #include <asm/io.h>
 #include <asm/machvec.h>
 #include <asm/numa.h>
@@ -668,10 +667,6 @@ mem_init (void)
                        fsyscall_table[i] = sys_call_table[i] | 1;
        }
        setup_gate();
-
-#ifdef CONFIG_IA32_SUPPORT
-       ia32_mem_init();
-#endif
 }
 
 #ifdef CONFIG_MEMORY_HOTPLUG
index 7a5ae633198b38ade2cf824619cbaf93cc0e3c33..f1490657bafc2a26fb2c7c5613d1e6f368a1706e 100644 (file)
@@ -104,7 +104,7 @@ void __init uv_setup(char **cmdline_p)
                uv_cpu_hub_info(cpu)->lowmem_remap_top =
                        lowmem_redir_base + lowmem_redir_size;
                uv_cpu_hub_info(cpu)->m_val = m_val;
-               uv_cpu_hub_info(cpu)->n_val = m_val;
+               uv_cpu_hub_info(cpu)->n_val = n_val;
                uv_cpu_hub_info(cpu)->pnode_mask = (1 << n_val) -1;
                uv_cpu_hub_info(cpu)->gpa_mask = (1 << (m_val + n_val)) - 1;
                uv_cpu_hub_info(cpu)->gnode_upper = gnode_upper;
index e32dae444dd6ec077f0f1ae259927aac723d5ec7..08847aa12583bd0a21534acec7fcea8391a19905 100644 (file)
@@ -58,11 +58,6 @@ __HCALL2(xen_ptcga, HYPERPRIVOP_PTC_GA)
 __HCALL2(xen_set_rr, HYPERPRIVOP_SET_RR)
 __HCALL2(xen_set_kr, HYPERPRIVOP_SET_KR)
 
-#ifdef CONFIG_IA32_SUPPORT
-__HCALL0(xen_get_eflag, HYPERPRIVOP_GET_EFLAG)
-__HCALL1(xen_set_eflag, HYPERPRIVOP_SET_EFLAG) // refer SDM vol1 3.1.8
-#endif /* CONFIG_IA32_SUPPORT */
-
 GLOBAL_ENTRY(xen_set_rr0_to_rr4)
        mov r8=r32
        mov r9=r33
index 5e2270a999fa58f410093c50cd30f92510c7a780..8adc6a14272abb990a104017eba40bf88aa2ebd0 100644 (file)
@@ -301,11 +301,6 @@ static void xen_setreg(int regnum, unsigned long val)
        case _IA64_REG_AR_KR0 ... _IA64_REG_AR_KR7:
                xen_set_kr(regnum - _IA64_REG_AR_KR0, val);
                break;
-#ifdef CONFIG_IA32_SUPPORT
-       case _IA64_REG_AR_EFLAG:
-               xen_set_eflag(val);
-               break;
-#endif
        case _IA64_REG_AR_ITC:
                xen_set_itc(val);
                break;
@@ -332,11 +327,6 @@ static unsigned long xen_getreg(int regnum)
        case _IA64_REG_PSR:
                res = xen_get_psr();
                break;
-#ifdef CONFIG_IA32_SUPPORT
-       case _IA64_REG_AR_EFLAG:
-               res = xen_get_eflag();
-               break;
-#endif
        case _IA64_REG_AR_ITC:
                res = xen_get_itc();
                break;
@@ -710,9 +700,6 @@ extern unsigned long xen_getreg(int regnum);
 
 __DEFINE_FUNC(getreg,
              __DEFINE_GET_REG(PSR, PSR)
-#ifdef CONFIG_IA32_SUPPORT
-             __DEFINE_GET_REG(AR_EFLAG, EFLAG)
-#endif
 
              /* get_itc */
              "mov r2 = " __stringify(_IA64_REG_AR_ITC) "\n"
@@ -789,9 +776,6 @@ __DEFINE_FUNC(setreg,
              ";;\n"
              "(p6) br.cond.spnt xen_set_itc\n"
 
-#ifdef CONFIG_IA32_SUPPORT
-             __DEFINE_SET_REG(AR_EFLAG, SET_EFLAG)
-#endif
              __DEFINE_SET_REG(CR_TPR, SET_TPR)
              __DEFINE_SET_REG(CR_EOI, EOI)
 
index 0ef95307784e0d9143cba8d2608d9f6cada5ca11..92614b0ccf1754e2cae1f653b30e797b613792d8 100644 (file)
@@ -92,6 +92,6 @@ static __inline__ void __flush_tlb_all(void)
        );
 }
 
-extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
+extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t *);
 
 #endif /* _ASM_M32R_TLBFLUSH_H */
index 88469178ea6bbfcd690a539c9a51e5ec02878f3f..888aab1157edaf1d13f6f2deee693ece3fb64ef2 100644 (file)
@@ -95,7 +95,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code,
  * update_mmu_cache()
  *======================================================================*/
 void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr,
-       pte_t pte)
+       pte_t *ptep)
 {
        BUG();
 }
index 7274b47f4c229b9d27aae0c6e787468fc07b8fb3..28ee389e5f5a3e43d39f8d5f1cdccf45923785d3 100644 (file)
@@ -336,7 +336,7 @@ vmalloc_fault:
 
                addr = (address & PAGE_MASK);
                set_thread_fault_code(error_code);
-               update_mmu_cache(NULL, addr, *pte_k);
+               update_mmu_cache(NULL, addr, pte_k);
                set_thread_fault_code(0);
                return;
        }
@@ -349,7 +349,7 @@ vmalloc_fault:
 #define ITLB_END       (unsigned long *)(ITLB_BASE + (NR_TLB_ENTRIES * 8))
 #define DTLB_END       (unsigned long *)(DTLB_BASE + (NR_TLB_ENTRIES * 8))
 void update_mmu_cache(struct vm_area_struct *vma, unsigned long vaddr,
-       pte_t pte)
+       pte_t *ptep)
 {
        volatile unsigned long *entry1, *entry2;
        unsigned long pte_data, flags;
@@ -365,7 +365,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long vaddr,
 
        vaddr = (vaddr & PAGE_MASK) | get_asid();
 
-       pte_data = pte_val(pte);
+       pte_data = pte_val(*ptep);
 
 #ifdef CONFIG_CHIP_OPSP
        entry1 = (unsigned long *)ITLB_BASE;
index aca0e28581c7733febbd2029a5c0a687f41b7485..87174c904d2b2e8eb5adc83a4fc056ac8790a9cc 100644 (file)
@@ -115,7 +115,7 @@ extern void kernel_set_cachemode(void *addr, unsigned long size, int cmode);
  * they are updated on demand.
  */
 static inline void update_mmu_cache(struct vm_area_struct *vma,
-                                   unsigned long address, pte_t pte)
+                                   unsigned long address, pte_t *ptep)
 {
 }
 
index eb31a0e8a7725cc843a3c19a16886fbae8e55ed6..10ec70cd8735446a2c5e0b938487fb6db0f6417a 100644 (file)
@@ -38,7 +38,7 @@ static inline void local_flush_tlb_range(struct vm_area_struct *vma,
 
 #define flush_tlb_kernel_range(start, end)     do { } while (0)
 
-#define update_mmu_cache(vma, addr, pte      do { } while (0)
+#define update_mmu_cache(vma, addr, ptep)      do { } while (0)
 
 #define flush_tlb_all local_flush_tlb_all
 #define flush_tlb_mm local_flush_tlb_mm
index 93598ba013556eaccdf5c37b6551d9111afd1683..7e40f37781790206a1174830f295258d89ec648f 100644 (file)
@@ -368,8 +368,9 @@ extern void __update_cache(struct vm_area_struct *vma, unsigned long address,
        pte_t pte);
 
 static inline void update_mmu_cache(struct vm_area_struct *vma,
-       unsigned long address, pte_t pte)
+       unsigned long address, pte_t *ptep)
 {
+       pte_t pte = *ptep;
        __update_tlb(vma, address, pte);
        __update_cache(vma, address, pte);
 }
index 6dc30fc827c458d5d2c6e67f964a79b720a96bdc..16d88577f3e08510b543452ac322d6cd7e970e77 100644 (file)
@@ -466,7 +466,7 @@ static inline int set_kernel_exec(unsigned long vaddr, int enable)
  * the kernel page tables containing the necessary information by tlb-mn10300.S
  */
 extern void update_mmu_cache(struct vm_area_struct *vma,
-                            unsigned long address, pte_t pte);
+                            unsigned long address, pte_t *ptep);
 
 #endif /* !__ASSEMBLY__ */
 
index 31c9d27a75ae8cab8a0e3daa650ddb8e8659febc..36ba02191d408251f9eaefa366610824e34d3d69 100644 (file)
@@ -51,9 +51,10 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
 /*
  * preemptively set a TLB entry
  */
-void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte)
+void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
 {
        unsigned long pteu, ptel, cnx, flags;
+       pte_t pte = *ptep;
 
        addr &= PAGE_MASK;
        ptel = pte_val(pte) & ~(xPTEL_UNUSED1 | xPTEL_UNUSED2);
index a27d2e200fb2a62519ba1dc281ebf0d3abe8f8be..01c15035e783d47ec944f7d47b30ee90202cd9a2 100644 (file)
@@ -410,7 +410,7 @@ extern void paging_init (void);
 
 #define PG_dcache_dirty         PG_arch_1
 
-extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
+extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t *);
 
 /* Encode and de-code a swap entry */
 
index b6ed34de14e15899cbcfccdbfa25cd80649282a6..1054baa2fc69000a17faa4bca451864cbdac2f0d 100644 (file)
@@ -68,9 +68,9 @@ flush_cache_all_local(void)
 EXPORT_SYMBOL(flush_cache_all_local);
 
 void
-update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
+update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep)
 {
-       struct page *page = pte_page(pte);
+       struct page *page = pte_page(*ptep);
 
        if (pfn_valid(page_to_pfn(page)) && page_mapping(page) &&
            test_bit(PG_dcache_dirty, &page->flags)) {
index 21207e54825b0566d5edf4c447c6d252ea76b497..89f158731ce37311b35225a43963b05227bf62c1 100644 (file)
@@ -209,7 +209,7 @@ extern void paging_init(void);
  * corresponding HPTE into the hash table ahead of time, instead of
  * waiting for the inevitable extra hash-table miss exception.
  */
-extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
+extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t *);
 
 extern int gup_hugepd(hugepd_t *hugepd, unsigned pdshift, unsigned long addr,
                      unsigned long end, int write, struct page **pages, int *nr);
index b9b152558f9c5de64d70399a37c1aa7dfd001706..311224cdb7ad08c53d0a8b70528b3bf888a4b795 100644 (file)
@@ -494,13 +494,13 @@ EXPORT_SYMBOL(flush_icache_user_range);
  * This must always be called with the pte lock held.
  */
 void update_mmu_cache(struct vm_area_struct *vma, unsigned long address,
-                     pte_t pte)
+                     pte_t *ptep)
 {
 #ifdef CONFIG_PPC_STD_MMU
        unsigned long access = 0, trap;
 
        /* We only want HPTEs for linux PTEs that have _PAGE_ACCESSED set */
-       if (!pte_young(pte) || address >= TASK_SIZE)
+       if (!pte_young(*ptep) || address >= TASK_SIZE)
                return;
 
        /* We try to figure out if we are coming from an instruction
index e2fa79cf06145d4b22fd15638c0cad644f9a8799..9b5b9189c15e86cc9f5053145324fe2123805ce9 100644 (file)
@@ -43,7 +43,7 @@ extern void vmem_map_init(void);
  * The S390 doesn't have any external MMU info: the kernel page
  * tables contain all the necessary information.
  */
-#define update_mmu_cache(vma, address, pte)     do { } while (0)
+#define update_mmu_cache(vma, address, ptep)     do { } while (0)
 
 /*
  * ZERO_PAGE is a global shared page that is always zero: used
index 674934b401703eec2ed153d70b7b42d22289e172..ccf38f06c57d78110e14cd21a0e3984c3c52b52d 100644 (file)
@@ -272,8 +272,9 @@ extern void __update_cache(struct vm_area_struct *vma,
        unsigned long address,  pte_t pte);
 
 static inline void update_mmu_cache(struct vm_area_struct *vma,
-       unsigned long address, pte_t pte)
+       unsigned long address, pte_t *ptep)
 {
+       pte_t pte = *ptep;
        __update_tlb(vma, address, pte);
        __update_cache(vma, address, pte);
 }
index aab76528abb979fe6d7b0c871aa03efb86396751..02f77450cd8f47af3071597916f1c509a7969ab4 100644 (file)
@@ -153,8 +153,9 @@ extern void __update_tlb(struct vm_area_struct *vma,
                         unsigned long address, pte_t pte);
 
 static inline void
-update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
+update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep)
 {
+       pte_t pte = *ptep;
        __update_cache(vma, address, pte);
        __update_tlb(vma, address, pte);
 }
diff --git a/arch/sh/include/asm/siu.h b/arch/sh/include/asm/siu.h
new file mode 100644 (file)
index 0000000..57565a3
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * platform header for the SIU ASoC driver
+ *
+ * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.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.
+ */
+
+#ifndef ASM_SIU_H
+#define ASM_SIU_H
+
+#include <asm/dma-sh.h>
+
+struct device;
+
+struct siu_platform {
+       struct device *dma_dev;
+       enum sh_dmae_slave_chan_id dma_slave_tx_a;
+       enum sh_dmae_slave_chan_id dma_slave_rx_a;
+       enum sh_dmae_slave_chan_id dma_slave_tx_b;
+       enum sh_dmae_slave_chan_id dma_slave_rx_b;
+};
+
+#endif /* ASM_SIU_H */
index 28e22839c665d8badf9c9aa359ed555fc3f8539e..8bf79e3b7bddb36af2c7f99a8093dccf512b59df 100644 (file)
@@ -374,7 +374,7 @@ handle_tlbmiss(struct pt_regs *regs, unsigned long writeaccess,
                local_flush_tlb_one(get_asid(), address & PAGE_MASK);
 #endif
 
-       update_mmu_cache(NULL, address, entry);
+       update_mmu_cache(NULL, address, pte);
 
        return 0;
 }
index e0cabe790ec134e762e27b410012d90389a95825..77f906d8cc21f3874ee079aa731edf49f02dea75 100644 (file)
@@ -330,9 +330,9 @@ BTFIXUPDEF_CALL(void, mmu_info, struct seq_file *)
 #define FAULT_CODE_WRITE    0x2
 #define FAULT_CODE_USER     0x4
 
-BTFIXUPDEF_CALL(void, update_mmu_cache, struct vm_area_struct *, unsigned long, pte_t)
+BTFIXUPDEF_CALL(void, update_mmu_cache, struct vm_area_struct *, unsigned long, pte_t *)
 
-#define update_mmu_cache(vma,addr,pte) BTFIXUP_CALL(update_mmu_cache)(vma,addr,pte)
+#define update_mmu_cache(vma,addr,ptep) BTFIXUP_CALL(update_mmu_cache)(vma,addr,ptep)
 
 BTFIXUPDEF_CALL(void, sparc_mapiorange, unsigned int, unsigned long,
     unsigned long, unsigned int)
index f3cb790fa2ae0771a4ac7b2b0ba7c73b14338111..f5b5fa76c02dbb2eb385220a5222c191f1bf2a8e 100644 (file)
@@ -706,7 +706,7 @@ extern unsigned long find_ecache_flush_span(unsigned long size);
 #define mmu_unlockarea(vaddr, len)             do { } while(0)
 
 struct vm_area_struct;
-extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
+extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t *);
 
 /* Encode and de-code a swap entry */
 #define __swp_type(entry)      (((entry).val >> PAGE_SHIFT) & 0xffUL)
index a3413acb8f127ce4bbd92d6305a83a9e428819fe..3fa09ba3845f3dafd06e80439e8214785d297f39 100644 (file)
@@ -378,7 +378,7 @@ asmlinkage void do_sun4c_fault(struct pt_regs *regs, int text_fault, int write,
                               unsigned long address)
 {
        extern void sun4c_update_mmu_cache(struct vm_area_struct *,
-                                          unsigned long,pte_t);
+                                          unsigned long,pte_t *);
        extern pte_t *sun4c_pte_offset_kernel(pmd_t *,unsigned long);
        struct task_struct *tsk = current;
        struct mm_struct *mm = tsk->mm;
@@ -455,7 +455,7 @@ asmlinkage void do_sun4c_fault(struct pt_regs *regs, int text_fault, int write,
                 *       on the CPU and doing a shrink_mmap() on this vma.
                 */
                sun4c_update_mmu_cache (find_vma(current->mm, address), address,
-                                       *ptep);
+                                       ptep);
        else
                do_sparc_fault(regs, text_fault, write, address);
 }
index 1886d37d411b2e129c9b711ca381d7856daead4f..9245a822a2f17cf8a20fc9edd12f217156f973ac 100644 (file)
@@ -289,12 +289,13 @@ static void flush_dcache(unsigned long pfn)
        }
 }
 
-void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
+void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep)
 {
        struct mm_struct *mm;
        struct tsb *tsb;
        unsigned long tag, flags;
        unsigned long tsb_index, tsb_hash_shift;
+       pte_t pte = *ptep;
 
        if (tlb_type != hypervisor) {
                unsigned long pfn = pte_pfn(pte);
index 196263f895b7d010eb7d40b1ab9a75b04599234b..4e62c27147c491843bf3747307cc3bc39e196d79 100644 (file)
@@ -62,7 +62,7 @@ pte_t *sun4c_pte_offset_kernel(pmd_t *dir, unsigned long address)
        return NULL;
 }
 
-void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
+void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep)
 {
 }
 
index 367321a030dd00de68506d9aa30f4cfec106eba0..df49b200ca4c12317077c44712d0f89f107ff872 100644 (file)
@@ -694,7 +694,7 @@ extern void tsunami_setup_blockops(void);
  * The following code is a deadwood that may be necessary when
  * we start to make precise page flushes again. --zaitcev
  */
-static void swift_update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte)
+static void swift_update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t *ptep)
 {
 #if 0
        static unsigned long last;
@@ -703,10 +703,10 @@ static void swift_update_mmu_cache(struct vm_area_struct * vma, unsigned long ad
 
        if (address == last) {
                val = srmmu_hwprobe(address);
-               if (val != 0 && pte_val(pte) != val) {
+               if (val != 0 && pte_val(*ptep) != val) {
                        printk("swift_update_mmu_cache: "
                            "addr %lx put %08x probed %08x from %p\n",
-                           address, pte_val(pte), val,
+                           address, pte_val(*ptep), val,
                            __builtin_return_address(0));
                        srmmu_flush_whole_tlb();
                }
index a89baf0d875af3ef7a557675b87a90398ee6fbd3..18652534b91a592a2dfb3c97cce676323fe471f2 100644 (file)
@@ -1887,7 +1887,7 @@ static void sun4c_check_pgt_cache(int low, int high)
 /* An experiment, turn off by default for now... -DaveM */
 #define SUN4C_PRELOAD_PSEG
 
-void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
+void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep)
 {
        unsigned long flags;
        int pseg;
@@ -1929,7 +1929,7 @@ void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, p
                        start += PAGE_SIZE;
                }
 #ifndef SUN4C_PRELOAD_PSEG
-               sun4c_put_pte(address, pte_val(pte));
+               sun4c_put_pte(address, pte_val(*ptep));
 #endif
                local_irq_restore(flags);
                return;
@@ -1940,7 +1940,7 @@ void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, p
                add_lru(entry);
        }
 
-       sun4c_put_pte(address, pte_val(pte));
+       sun4c_put_pte(address, pte_val(*ptep));
        local_irq_restore(flags);
 }
 
index 5ff554677f4019ad4435bb6d8277b9ec72907d97..c1ff6903b622126789945164c0a33101d0a7943a 100644 (file)
@@ -747,7 +747,7 @@ static int ubd_open_dev(struct ubd *ubd_dev)
        ubd_dev->fd = fd;
 
        if(ubd_dev->cow.file != NULL){
-               blk_queue_max_sectors(ubd_dev->queue, 8 * sizeof(long));
+               blk_queue_max_hw_sectors(ubd_dev->queue, 8 * sizeof(long));
 
                err = -ENOMEM;
                ubd_dev->cow.bitmap = vmalloc(ubd_dev->cow.bitmap_len);
@@ -849,7 +849,7 @@ static int ubd_add(int n, char **error_out)
        }
        ubd_dev->queue->queuedata = ubd_dev;
 
-       blk_queue_max_hw_segments(ubd_dev->queue, MAX_SG);
+       blk_queue_max_segments(ubd_dev->queue, MAX_SG);
        err = ubd_disk_register(UBD_MAJOR, ubd_dev->size, n, &ubd_gendisk[n]);
        if(err){
                *error_out = "Failed to register device";
index 9ce3f165111a63607fa91f98a99e3b232fb5080a..a9f7251b4a8dcadd347d7a8d71043e5b312ff673 100644 (file)
@@ -345,7 +345,7 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 struct mm_struct;
 extern pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr);
 
-#define update_mmu_cache(vma,address,pte) do ; while (0)
+#define update_mmu_cache(vma,address,ptep) do ; while (0)
 
 /* Encode and de-code a swap entry */
 #define __swp_type(x)                  (((x).val >> 4) & 0x3f)
index 01fd9461d323b89827afdc9a5a4c205a6bae3407..a28668396508df140ad62ecee2fb330f4ce6bc08 100644 (file)
@@ -80,7 +80,7 @@ do {                                          \
  * The i386 doesn't have any external MMU info: the kernel page
  * tables contain all the necessary information.
  */
-#define update_mmu_cache(vma, address, pte) do { } while (0)
+#define update_mmu_cache(vma, address, ptep) do { } while (0)
 
 #endif /* !__ASSEMBLY__ */
 
index c57a301171496e7b7af33ad3227bcdac5ae45c01..181be528c6128a716f5e19e41d19a054a963ba6e 100644 (file)
@@ -129,7 +129,7 @@ static inline int pgd_large(pgd_t pgd) { return 0; }
 #define pte_unmap(pte) /* NOP */
 #define pte_unmap_nested(pte) /* NOP */
 
-#define update_mmu_cache(vma, address, pte) do { } while (0)
+#define update_mmu_cache(vma, address, ptep) do { } while (0)
 
 /* Encode and de-code a swap entry */
 #if _PAGE_BIT_FILE < _PAGE_BIT_PROTNONE
index 6e44519960c8f6413c3f0f54ba85ed591f172e81..d360b56e9825e43e16b185b00746a016e806c1f5 100644 (file)
@@ -806,7 +806,7 @@ static int find_psb_table(struct powernow_k8_data *data)
 static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data,
                unsigned int index)
 {
-       acpi_integer control;
+       u64 control;
 
        if (!data->acpi_data.state_count || (cpu_family == CPU_HW_PSTATE))
                return;
@@ -824,7 +824,7 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
 {
        struct cpufreq_frequency_table *powernow_table;
        int ret_val = -ENODEV;
-       acpi_integer control, status;
+       u64 control, status;
 
        if (acpi_processor_register_performance(&data->acpi_data, data->cpu)) {
                dprintk("register performance failed: bad ACPI data\n");
@@ -948,7 +948,7 @@ static int fill_powernow_table_fidvid(struct powernow_k8_data *data,
                u32 fid;
                u32 vid;
                u32 freq, index;
-               acpi_integer status, control;
+               u64 status, control;
 
                if (data->exttype) {
                        status =  data->acpi_data.states[i].status;
index ad80a1c718c6e53e9dd1b1cecac342393289ae73..ee4fa1bfcb33354b96069b4728dd5cf367e74e12 100644 (file)
@@ -266,7 +266,7 @@ static void hpet_resume_device(void)
        force_hpet_resume();
 }
 
-static void hpet_resume_counter(void)
+static void hpet_resume_counter(struct clocksource *cs)
 {
        hpet_resume_device();
        hpet_restart_counter();
index 23066ecf12fa2a61db86e9c0c4e8db8a89dfb307..208a857c679f99a9dd7e1902f35b8b56d16a0fca 100644 (file)
@@ -740,7 +740,7 @@ static cycle_t __vsyscall_fn vread_tsc(void)
 }
 #endif
 
-static void resume_tsc(void)
+static void resume_tsc(struct clocksource *cs)
 {
        clocksource_tsc.cycle_last = 0;
 }
index a138770c358ed1d134fcb0274b93f4eeee515757..76bf35554117d8044de73e9b3e1138e562379c0c 100644 (file)
@@ -394,7 +394,7 @@ ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 #define kern_addr_valid(addr)  (1)
 
 extern  void update_mmu_cache(struct vm_area_struct * vma,
-                             unsigned long address, pte_t pte);
+                             unsigned long address, pte_t *ptep);
 
 /*
  * remap a physical page `pfn' of size `size' with page protection `prot'
index 3ba990c67676c0b40976ff60d03638ceefba94cd..85df4655d3264d8afda978c5ed0a229567b43989 100644 (file)
@@ -147,9 +147,9 @@ void flush_cache_page(struct vm_area_struct* vma, unsigned long address,
 #endif
 
 void
-update_mmu_cache(struct vm_area_struct * vma, unsigned long addr, pte_t pte)
+update_mmu_cache(struct vm_area_struct * vma, unsigned long addr, pte_t *ptep)
 {
-       unsigned long pfn = pte_pfn(pte);
+       unsigned long pfn = pte_pfn(*ptep);
        struct page *page;
 
        if (!pfn_valid(pfn))
index e7dbbaf5fb3ee58698b1692508b991da8d38accd..c85d74cae200275b168f5291770073ad3540347f 100644 (file)
@@ -23,20 +23,6 @@ static LIST_HEAD(blkio_list);
 struct blkio_cgroup blkio_root_cgroup = { .weight = 2*BLKIO_WEIGHT_DEFAULT };
 EXPORT_SYMBOL_GPL(blkio_root_cgroup);
 
-bool blkiocg_css_tryget(struct blkio_cgroup *blkcg)
-{
-       if (!css_tryget(&blkcg->css))
-               return false;
-       return true;
-}
-EXPORT_SYMBOL_GPL(blkiocg_css_tryget);
-
-void blkiocg_css_put(struct blkio_cgroup *blkcg)
-{
-       css_put(&blkcg->css);
-}
-EXPORT_SYMBOL_GPL(blkiocg_css_put);
-
 struct blkio_cgroup *cgroup_to_blkio_cgroup(struct cgroup *cgroup)
 {
        return container_of(cgroup_subsys_state(cgroup, blkio_subsys_id),
index 4d316df863b47bf16d2b277998e6c9a3592959d3..84bf745fa77576898b8c01c13bd68879092bf869 100644 (file)
@@ -43,9 +43,6 @@ struct blkio_group {
        unsigned long sectors;
 };
 
-extern bool blkiocg_css_tryget(struct blkio_cgroup *blkcg);
-extern void blkiocg_css_put(struct blkio_cgroup *blkcg);
-
 typedef void (blkio_unlink_group_fn) (void *key, struct blkio_group *blkg);
 typedef void (blkio_update_group_weight_fn) (struct blkio_group *blkg,
                                                unsigned int weight);
index d1a9a0a64f95b5295314bec0ef6c2e96d99775b2..9fe174dc74d1dfecca76bb19eb9dda2af53f93bd 100644 (file)
@@ -1490,9 +1490,9 @@ end_io:
 /*
  * We only want one ->make_request_fn to be active at a time,
  * else stack usage with stacked devices could be a problem.
- * So use current->bio_{list,tail} to keep a list of requests
+ * So use current->bio_list to keep a list of requests
  * submited by a make_request_fn function.
- * current->bio_tail is also used as a flag to say if
+ * current->bio_list is also used as a flag to say if
  * generic_make_request is currently active in this task or not.
  * If it is NULL, then no make_request is active.  If it is non-NULL,
  * then a make_request is active, and new requests should be added
@@ -1500,11 +1500,11 @@ end_io:
  */
 void generic_make_request(struct bio *bio)
 {
-       if (current->bio_tail) {
+       struct bio_list bio_list_on_stack;
+
+       if (current->bio_list) {
                /* make_request is active */
-               *(current->bio_tail) = bio;
-               bio->bi_next = NULL;
-               current->bio_tail = &bio->bi_next;
+               bio_list_add(current->bio_list, bio);
                return;
        }
        /* following loop may be a bit non-obvious, and so deserves some
@@ -1512,30 +1512,27 @@ void generic_make_request(struct bio *bio)
         * Before entering the loop, bio->bi_next is NULL (as all callers
         * ensure that) so we have a list with a single bio.
         * We pretend that we have just taken it off a longer list, so
-        * we assign bio_list to the next (which is NULL) and bio_tail
-        * to &bio_list, thus initialising the bio_list of new bios to be
+        * we assign bio_list to a pointer to the bio_list_on_stack,
+        * thus initialising the bio_list of new bios to be
         * added.  __generic_make_request may indeed add some more bios
         * through a recursive call to generic_make_request.  If it
         * did, we find a non-NULL value in bio_list and re-enter the loop
         * from the top.  In this case we really did just take the bio
-        * of the top of the list (no pretending) and so fixup bio_list and
-        * bio_tail or bi_next, and call into __generic_make_request again.
+        * of the top of the list (no pretending) and so remove it from
+        * bio_list, and call into __generic_make_request again.
         *
         * The loop was structured like this to make only one call to
         * __generic_make_request (which is important as it is large and
         * inlined) and to keep the structure simple.
         */
        BUG_ON(bio->bi_next);
+       bio_list_init(&bio_list_on_stack);
+       current->bio_list = &bio_list_on_stack;
        do {
-               current->bio_list = bio->bi_next;
-               if (bio->bi_next == NULL)
-                       current->bio_tail = &current->bio_list;
-               else
-                       bio->bi_next = NULL;
                __generic_make_request(bio);
-               bio = current->bio_list;
+               bio = bio_list_pop(current->bio_list);
        } while (bio);
-       current->bio_tail = NULL; /* deactivate */
+       current->bio_list = NULL; /* deactivate */
 }
 EXPORT_SYMBOL(generic_make_request);
 
@@ -1617,8 +1614,7 @@ int blk_rq_check_limits(struct request_queue *q, struct request *rq)
         * limitation.
         */
        blk_recalc_rq_segments(rq);
-       if (rq->nr_phys_segments > queue_max_phys_segments(q) ||
-           rq->nr_phys_segments > queue_max_hw_segments(q)) {
+       if (rq->nr_phys_segments > queue_max_segments(q)) {
                printk(KERN_ERR "%s: over max segments limit.\n", __func__);
                return -EIO;
        }
index 98e6bf61b0ac8c505aac61ae37cc27b89a49cb55..3f65c8aadb2fb9ba6116f82653e314efce950a51 100644 (file)
@@ -91,7 +91,7 @@ struct io_context *alloc_io_context(gfp_t gfp_flags, int node)
                spin_lock_init(&ret->lock);
                ret->ioprio_changed = 0;
                ret->ioprio = 0;
-               ret->last_waited = jiffies; /* doesn't matter... */
+               ret->last_waited = 0; /* doesn't matter... */
                ret->nr_batch_requests = 0; /* because this is 0 */
                INIT_RADIX_TREE(&ret->radix_root, GFP_ATOMIC | __GFP_HIGH);
                INIT_HLIST_HEAD(&ret->cic_list);
index 99cb5cf1f447fa8759d73f06bf64fe4b20eec580..5e7dc9973458406c5159b8ea3b87033302bf5fcf 100644 (file)
@@ -206,8 +206,7 @@ static inline int ll_new_hw_segment(struct request_queue *q,
 {
        int nr_phys_segs = bio_phys_segments(q, bio);
 
-       if (req->nr_phys_segments + nr_phys_segs > queue_max_hw_segments(q) ||
-           req->nr_phys_segments + nr_phys_segs > queue_max_phys_segments(q)) {
+       if (req->nr_phys_segments + nr_phys_segs > queue_max_segments(q)) {
                req->cmd_flags |= REQ_NOMERGE;
                if (req == q->last_merge)
                        q->last_merge = NULL;
@@ -300,10 +299,7 @@ static int ll_merge_requests_fn(struct request_queue *q, struct request *req,
                total_phys_segments--;
        }
 
-       if (total_phys_segments > queue_max_phys_segments(q))
-               return 0;
-
-       if (total_phys_segments > queue_max_hw_segments(q))
+       if (total_phys_segments > queue_max_segments(q))
                return 0;
 
        /* Merge is OK... */
index 5eeb9e0d256ea7c9afd9fc72eacdbb46cc11b46a..31e7a9375c1333cc35ab40d565c5c1ed4e8703e7 100644 (file)
@@ -91,10 +91,9 @@ EXPORT_SYMBOL_GPL(blk_queue_lld_busy);
  */
 void blk_set_default_limits(struct queue_limits *lim)
 {
-       lim->max_phys_segments = MAX_PHYS_SEGMENTS;
-       lim->max_hw_segments = MAX_HW_SEGMENTS;
+       lim->max_segments = BLK_MAX_SEGMENTS;
        lim->seg_boundary_mask = BLK_SEG_BOUNDARY_MASK;
-       lim->max_segment_size = MAX_SEGMENT_SIZE;
+       lim->max_segment_size = BLK_MAX_SEGMENT_SIZE;
        lim->max_sectors = BLK_DEF_MAX_SECTORS;
        lim->max_hw_sectors = INT_MAX;
        lim->max_discard_sectors = 0;
@@ -154,7 +153,7 @@ void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn)
        q->unplug_timer.data = (unsigned long)q;
 
        blk_set_default_limits(&q->limits);
-       blk_queue_max_sectors(q, SAFE_MAX_SECTORS);
+       blk_queue_max_hw_sectors(q, BLK_SAFE_MAX_SECTORS);
 
        /*
         * If the caller didn't supply a lock, fall back to our embedded
@@ -210,37 +209,32 @@ void blk_queue_bounce_limit(struct request_queue *q, u64 dma_mask)
 EXPORT_SYMBOL(blk_queue_bounce_limit);
 
 /**
- * blk_queue_max_sectors - set max sectors for a request for this queue
+ * blk_queue_max_hw_sectors - set max sectors for a request for this queue
  * @q:  the request queue for the device
- * @max_sectors:  max sectors in the usual 512b unit
+ * @max_hw_sectors:  max hardware sectors in the usual 512b unit
  *
  * Description:
- *    Enables a low level driver to set an upper limit on the size of
- *    received requests.
+ *    Enables a low level driver to set a hard upper limit,
+ *    max_hw_sectors, on the size of requests.  max_hw_sectors is set by
+ *    the device driver based upon the combined capabilities of I/O
+ *    controller and storage device.
+ *
+ *    max_sectors is a soft limit imposed by the block layer for
+ *    filesystem type requests.  This value can be overridden on a
+ *    per-device basis in /sys/block/<device>/queue/max_sectors_kb.
+ *    The soft limit can not exceed max_hw_sectors.
  **/
-void blk_queue_max_sectors(struct request_queue *q, unsigned int max_sectors)
+void blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_hw_sectors)
 {
-       if ((max_sectors << 9) < PAGE_CACHE_SIZE) {
-               max_sectors = 1 << (PAGE_CACHE_SHIFT - 9);
+       if ((max_hw_sectors << 9) < PAGE_CACHE_SIZE) {
+               max_hw_sectors = 1 << (PAGE_CACHE_SHIFT - 9);
                printk(KERN_INFO "%s: set to minimum %d\n",
-                      __func__, max_sectors);
+                      __func__, max_hw_sectors);
        }
 
-       if (BLK_DEF_MAX_SECTORS > max_sectors)
-               q->limits.max_hw_sectors = q->limits.max_sectors = max_sectors;
-       else {
-               q->limits.max_sectors = BLK_DEF_MAX_SECTORS;
-               q->limits.max_hw_sectors = max_sectors;
-       }
-}
-EXPORT_SYMBOL(blk_queue_max_sectors);
-
-void blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_sectors)
-{
-       if (BLK_DEF_MAX_SECTORS > max_sectors)
-               q->limits.max_hw_sectors = BLK_DEF_MAX_SECTORS;
-       else
-               q->limits.max_hw_sectors = max_sectors;
+       q->limits.max_hw_sectors = max_hw_sectors;
+       q->limits.max_sectors = min_t(unsigned int, max_hw_sectors,
+                                     BLK_DEF_MAX_SECTORS);
 }
 EXPORT_SYMBOL(blk_queue_max_hw_sectors);
 
@@ -257,17 +251,15 @@ void blk_queue_max_discard_sectors(struct request_queue *q,
 EXPORT_SYMBOL(blk_queue_max_discard_sectors);
 
 /**
- * blk_queue_max_phys_segments - set max phys segments for a request for this queue
+ * blk_queue_max_segments - set max hw segments for a request for this queue
  * @q:  the request queue for the device
  * @max_segments:  max number of segments
  *
  * Description:
  *    Enables a low level driver to set an upper limit on the number of
- *    physical data segments in a request.  This would be the largest sized
- *    scatter list the driver could handle.
+ *    hw data segments in a request.
  **/
-void blk_queue_max_phys_segments(struct request_queue *q,
-                                unsigned short max_segments)
+void blk_queue_max_segments(struct request_queue *q, unsigned short max_segments)
 {
        if (!max_segments) {
                max_segments = 1;
@@ -275,33 +267,9 @@ void blk_queue_max_phys_segments(struct request_queue *q,
                       __func__, max_segments);
        }
 
-       q->limits.max_phys_segments = max_segments;
+       q->limits.max_segments = max_segments;
 }
-EXPORT_SYMBOL(blk_queue_max_phys_segments);
-
-/**
- * blk_queue_max_hw_segments - set max hw segments for a request for this queue
- * @q:  the request queue for the device
- * @max_segments:  max number of segments
- *
- * Description:
- *    Enables a low level driver to set an upper limit on the number of
- *    hw data segments in a request.  This would be the largest number of
- *    address/length pairs the host adapter can actually give at once
- *    to the device.
- **/
-void blk_queue_max_hw_segments(struct request_queue *q,
-                              unsigned short max_segments)
-{
-       if (!max_segments) {
-               max_segments = 1;
-               printk(KERN_INFO "%s: set to minimum %d\n",
-                      __func__, max_segments);
-       }
-
-       q->limits.max_hw_segments = max_segments;
-}
-EXPORT_SYMBOL(blk_queue_max_hw_segments);
+EXPORT_SYMBOL(blk_queue_max_segments);
 
 /**
  * blk_queue_max_segment_size - set max segment size for blk_rq_map_sg
@@ -507,7 +475,7 @@ static unsigned int lcm(unsigned int a, unsigned int b)
  * blk_stack_limits - adjust queue_limits for stacked devices
  * @t: the stacking driver limits (top device)
  * @b:  the underlying queue limits (bottom, component device)
- * @offset:  offset to beginning of data within component device
+ * @start:  first data sector within component device
  *
  * Description:
  *    This function is used by stacking drivers like MD and DM to ensure
@@ -525,10 +493,9 @@ static unsigned int lcm(unsigned int a, unsigned int b)
  *    the alignment_offset is undefined.
  */
 int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
-                    sector_t offset)
+                    sector_t start)
 {
-       sector_t alignment;
-       unsigned int top, bottom, ret = 0;
+       unsigned int top, bottom, alignment, ret = 0;
 
        t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors);
        t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors);
@@ -537,18 +504,14 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
        t->seg_boundary_mask = min_not_zero(t->seg_boundary_mask,
                                            b->seg_boundary_mask);
 
-       t->max_phys_segments = min_not_zero(t->max_phys_segments,
-                                           b->max_phys_segments);
-
-       t->max_hw_segments = min_not_zero(t->max_hw_segments,
-                                         b->max_hw_segments);
+       t->max_segments = min_not_zero(t->max_segments, b->max_segments);
 
        t->max_segment_size = min_not_zero(t->max_segment_size,
                                           b->max_segment_size);
 
        t->misaligned |= b->misaligned;
 
-       alignment = queue_limit_alignment_offset(b, offset);
+       alignment = queue_limit_alignment_offset(b, start);
 
        /* Bottom device has different alignment.  Check that it is
         * compatible with the current top alignment.
@@ -611,11 +574,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
 
        /* Discard alignment and granularity */
        if (b->discard_granularity) {
-               unsigned int granularity = b->discard_granularity;
-               offset &= granularity - 1;
-
-               alignment = (granularity + b->discard_alignment - offset)
-                       & (granularity - 1);
+               alignment = queue_limit_discard_alignment(b, start);
 
                if (t->discard_granularity != 0 &&
                    t->discard_alignment != alignment) {
@@ -657,7 +616,7 @@ int bdev_stack_limits(struct queue_limits *t, struct block_device *bdev,
 
        start += get_start_sect(bdev);
 
-       return blk_stack_limits(t, &bq->limits, start << 9);
+       return blk_stack_limits(t, &bq->limits, start);
 }
 EXPORT_SYMBOL(bdev_stack_limits);
 
@@ -668,9 +627,8 @@ EXPORT_SYMBOL(bdev_stack_limits);
  * @offset:  offset to beginning of data within component device
  *
  * Description:
- *    Merges the limits for two queues.  Returns 0 if alignment
- *    didn't change.  Returns -1 if adding the bottom device caused
- *    misalignment.
+ *    Merges the limits for a top level gendisk and a bottom level
+ *    block_device.
  */
 void disk_stack_limits(struct gendisk *disk, struct block_device *bdev,
                       sector_t offset)
@@ -678,9 +636,7 @@ void disk_stack_limits(struct gendisk *disk, struct block_device *bdev,
        struct request_queue *t = disk->queue;
        struct request_queue *b = bdev_get_queue(bdev);
 
-       offset += get_start_sect(bdev) << 9;
-
-       if (blk_stack_limits(&t->limits, &b->limits, offset) < 0) {
+       if (bdev_stack_limits(&t->limits, bdev, offset >> 9) < 0) {
                char top[BDEVNAME_SIZE], bottom[BDEVNAME_SIZE];
 
                disk_name(disk, 0, top);
@@ -752,22 +708,19 @@ EXPORT_SYMBOL(blk_queue_update_dma_pad);
  * does is adjust the queue so that the buf is always appended
  * silently to the scatterlist.
  *
- * Note: This routine adjusts max_hw_segments to make room for
- * appending the drain buffer.  If you call
- * blk_queue_max_hw_segments() or blk_queue_max_phys_segments() after
- * calling this routine, you must set the limit to one fewer than your
- * device can support otherwise there won't be room for the drain
- * buffer.
+ * Note: This routine adjusts max_hw_segments to make room for appending
+ * the drain buffer.  If you call blk_queue_max_segments() after calling
+ * this routine, you must set the limit to one fewer than your device
+ * can support otherwise there won't be room for the drain buffer.
  */
 int blk_queue_dma_drain(struct request_queue *q,
                               dma_drain_needed_fn *dma_drain_needed,
                               void *buf, unsigned int size)
 {
-       if (queue_max_hw_segments(q) < 2 || queue_max_phys_segments(q) < 2)
+       if (queue_max_segments(q) < 2)
                return -EINVAL;
        /* make room for appending the drain */
-       blk_queue_max_hw_segments(q, queue_max_hw_segments(q) - 1);
-       blk_queue_max_phys_segments(q, queue_max_phys_segments(q) - 1);
+       blk_queue_max_segments(q, queue_max_segments(q) - 1);
        q->dma_drain_needed = dma_drain_needed;
        q->dma_drain_buffer = buf;
        q->dma_drain_size = size;
index 8606c9543fdda0368c6bdde8b4af2d00584e674d..e85442415db34174f5ea4efce83cc0912813adcc 100644 (file)
@@ -189,7 +189,8 @@ static ssize_t queue_nonrot_store(struct request_queue *q, const char *page,
 
 static ssize_t queue_nomerges_show(struct request_queue *q, char *page)
 {
-       return queue_var_show(blk_queue_nomerges(q), page);
+       return queue_var_show((blk_queue_nomerges(q) << 1) |
+                              blk_queue_noxmerges(q), page);
 }
 
 static ssize_t queue_nomerges_store(struct request_queue *q, const char *page,
@@ -199,10 +200,12 @@ static ssize_t queue_nomerges_store(struct request_queue *q, const char *page,
        ssize_t ret = queue_var_store(&nm, page, count);
 
        spin_lock_irq(q->queue_lock);
-       if (nm)
+       queue_flag_clear(QUEUE_FLAG_NOMERGES, q);
+       queue_flag_clear(QUEUE_FLAG_NOXMERGES, q);
+       if (nm == 2)
                queue_flag_set(QUEUE_FLAG_NOMERGES, q);
-       else
-               queue_flag_clear(QUEUE_FLAG_NOMERGES, q);
+       else if (nm)
+               queue_flag_set(QUEUE_FLAG_NOXMERGES, q);
        spin_unlock_irq(q->queue_lock);
 
        return ret;
index 023f4e69a3378cab44faefbf6c69823e6ec16b48..dee9d9378fee18658875fba10122ed0cbe308d04 100644 (file)
@@ -19,7 +19,7 @@
  * tunables
  */
 /* max queue in one round of service */
-static const int cfq_quantum = 4;
+static const int cfq_quantum = 8;
 static const int cfq_fifo_expire[2] = { HZ / 4, HZ / 8 };
 /* maximum backwards seek, in KiB */
 static const int cfq_back_max = 16 * 1024;
@@ -46,8 +46,9 @@ static const int cfq_hist_divisor = 4;
 #define CFQ_HW_QUEUE_MIN       (5)
 #define CFQ_SERVICE_SHIFT       12
 
-#define CFQQ_SEEK_THR          8 * 1024
-#define CFQQ_SEEKY(cfqq)       ((cfqq)->seek_mean > CFQQ_SEEK_THR)
+#define CFQQ_SEEK_THR          (sector_t)(8 * 100)
+#define CFQQ_SECT_THR_NONROT   (sector_t)(2 * 32)
+#define CFQQ_SEEKY(cfqq)       (hweight32(cfqq->seek_history) > 32/8)
 
 #define RQ_CIC(rq)             \
        ((struct cfq_io_context *) (rq)->elevator_private)
@@ -77,11 +78,12 @@ struct cfq_rb_root {
        struct rb_root rb;
        struct rb_node *left;
        unsigned count;
+       unsigned total_weight;
        u64 min_vdisktime;
        struct rb_node *active;
-       unsigned total_weight;
 };
-#define CFQ_RB_ROOT    (struct cfq_rb_root) { RB_ROOT, NULL, 0, 0, }
+#define CFQ_RB_ROOT    (struct cfq_rb_root) { .rb = RB_ROOT, .left = NULL, \
+                       .count = 0, .min_vdisktime = 0, }
 
 /*
  * Per process-grouping structure
@@ -115,11 +117,11 @@ struct cfq_queue {
        /* time when queue got scheduled in to dispatch first request. */
        unsigned long dispatch_start;
        unsigned int allocated_slice;
+       unsigned int slice_dispatch;
        /* time when first request from queue completed and slice started. */
        unsigned long slice_start;
        unsigned long slice_end;
        long slice_resid;
-       unsigned int slice_dispatch;
 
        /* pending metadata requests */
        int meta_pending;
@@ -130,13 +132,11 @@ struct cfq_queue {
        unsigned short ioprio, org_ioprio;
        unsigned short ioprio_class, org_ioprio_class;
 
-       unsigned int seek_samples;
-       u64 seek_total;
-       sector_t seek_mean;
-       sector_t last_request_pos;
-
        pid_t pid;
 
+       u32 seek_history;
+       sector_t last_request_pos;
+
        struct cfq_rb_root *service_tree;
        struct cfq_queue *new_cfqq;
        struct cfq_group *cfqg;
@@ -223,8 +223,8 @@ struct cfq_data {
 
        unsigned int busy_queues;
 
-       int rq_in_driver[2];
-       int sync_flight;
+       int rq_in_driver;
+       int rq_in_flight[2];
 
        /*
         * queue-depth detection
@@ -417,11 +417,6 @@ static struct cfq_queue *cfq_get_queue(struct cfq_data *, bool,
 static struct cfq_io_context *cfq_cic_lookup(struct cfq_data *,
                                                struct io_context *);
 
-static inline int rq_in_driver(struct cfq_data *cfqd)
-{
-       return cfqd->rq_in_driver[0] + cfqd->rq_in_driver[1];
-}
-
 static inline struct cfq_queue *cic_to_cfqq(struct cfq_io_context *cic,
                                            bool is_sync)
 {
@@ -951,10 +946,6 @@ cfq_find_alloc_cfqg(struct cfq_data *cfqd, struct cgroup *cgroup, int create)
        struct backing_dev_info *bdi = &cfqd->queue->backing_dev_info;
        unsigned int major, minor;
 
-       /* Do we need to take this reference */
-       if (!blkiocg_css_tryget(blkcg))
-               return NULL;;
-
        cfqg = cfqg_of_blkg(blkiocg_lookup_group(blkcg, key));
        if (cfqg || !create)
                goto done;
@@ -985,7 +976,6 @@ cfq_find_alloc_cfqg(struct cfq_data *cfqd, struct cgroup *cgroup, int create)
        hlist_add_head(&cfqg->cfqd_node, &cfqd->cfqg_list);
 
 done:
-       blkiocg_css_put(blkcg);
        return cfqg;
 }
 
@@ -1420,9 +1410,9 @@ static void cfq_activate_request(struct request_queue *q, struct request *rq)
 {
        struct cfq_data *cfqd = q->elevator->elevator_data;
 
-       cfqd->rq_in_driver[rq_is_sync(rq)]++;
+       cfqd->rq_in_driver++;
        cfq_log_cfqq(cfqd, RQ_CFQQ(rq), "activate rq, drv=%d",
-                                               rq_in_driver(cfqd));
+                                               cfqd->rq_in_driver);
 
        cfqd->last_position = blk_rq_pos(rq) + blk_rq_sectors(rq);
 }
@@ -1430,12 +1420,11 @@ static void cfq_activate_request(struct request_queue *q, struct request *rq)
 static void cfq_deactivate_request(struct request_queue *q, struct request *rq)
 {
        struct cfq_data *cfqd = q->elevator->elevator_data;
-       const int sync = rq_is_sync(rq);
 
-       WARN_ON(!cfqd->rq_in_driver[sync]);
-       cfqd->rq_in_driver[sync]--;
+       WARN_ON(!cfqd->rq_in_driver);
+       cfqd->rq_in_driver--;
        cfq_log_cfqq(cfqd, RQ_CFQQ(rq), "deactivate rq, drv=%d",
-                                               rq_in_driver(cfqd));
+                                               cfqd->rq_in_driver);
 }
 
 static void cfq_remove_request(struct request *rq)
@@ -1673,16 +1662,7 @@ static inline sector_t cfq_dist_from_last(struct cfq_data *cfqd,
 static inline int cfq_rq_close(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                               struct request *rq, bool for_preempt)
 {
-       sector_t sdist = cfqq->seek_mean;
-
-       if (!sample_valid(cfqq->seek_samples))
-               sdist = CFQQ_SEEK_THR;
-
-       /* if seek_mean is big, using it as close criteria is meaningless */
-       if (sdist > CFQQ_SEEK_THR && !for_preempt)
-               sdist = CFQQ_SEEK_THR;
-
-       return cfq_dist_from_last(cfqd, rq) <= sdist;
+       return cfq_dist_from_last(cfqd, rq) <= CFQQ_SEEK_THR;
 }
 
 static struct cfq_queue *cfqq_close(struct cfq_data *cfqd,
@@ -1878,8 +1858,7 @@ static void cfq_dispatch_insert(struct request_queue *q, struct request *rq)
        cfqq->dispatched++;
        elv_dispatch_sort(q, rq);
 
-       if (cfq_cfqq_sync(cfqq))
-               cfqd->sync_flight++;
+       cfqd->rq_in_flight[cfq_cfqq_sync(cfqq)]++;
        cfqq->nr_sectors += blk_rq_sectors(rq);
 }
 
@@ -2219,6 +2198,19 @@ static int cfq_forced_dispatch(struct cfq_data *cfqd)
        return dispatched;
 }
 
+static inline bool cfq_slice_used_soon(struct cfq_data *cfqd,
+       struct cfq_queue *cfqq)
+{
+       /* the queue hasn't finished any request, can't estimate */
+       if (cfq_cfqq_slice_new(cfqq))
+               return 1;
+       if (time_after(jiffies + cfqd->cfq_slice_idle * cfqq->dispatched,
+               cfqq->slice_end))
+               return 1;
+
+       return 0;
+}
+
 static bool cfq_may_dispatch(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
        unsigned int max_dispatch;
@@ -2226,16 +2218,16 @@ static bool cfq_may_dispatch(struct cfq_data *cfqd, struct cfq_queue *cfqq)
        /*
         * Drain async requests before we start sync IO
         */
-       if (cfq_should_idle(cfqd, cfqq) && cfqd->rq_in_driver[BLK_RW_ASYNC])
+       if (cfq_should_idle(cfqd, cfqq) && cfqd->rq_in_flight[BLK_RW_ASYNC])
                return false;
 
        /*
         * If this is an async queue and we have sync IO in flight, let it wait
         */
-       if (cfqd->sync_flight && !cfq_cfqq_sync(cfqq))
+       if (cfqd->rq_in_flight[BLK_RW_SYNC] && !cfq_cfqq_sync(cfqq))
                return false;
 
-       max_dispatch = cfqd->cfq_quantum;
+       max_dispatch = max_t(unsigned int, cfqd->cfq_quantum / 2, 1);
        if (cfq_class_idle(cfqq))
                max_dispatch = 1;
 
@@ -2252,13 +2244,22 @@ static bool cfq_may_dispatch(struct cfq_data *cfqd, struct cfq_queue *cfqq)
                /*
                 * We have other queues, don't allow more IO from this one
                 */
-               if (cfqd->busy_queues > 1)
+               if (cfqd->busy_queues > 1 && cfq_slice_used_soon(cfqd, cfqq))
                        return false;
 
                /*
                 * Sole queue user, no limit
                 */
-               max_dispatch = -1;
+               if (cfqd->busy_queues == 1)
+                       max_dispatch = -1;
+               else
+                       /*
+                        * Normally we start throttling cfqq when cfq_quantum/2
+                        * requests have been dispatched. But we can drive
+                        * deeper queue depths at the beginning of slice
+                        * subjected to upper limit of cfq_quantum.
+                        * */
+                       max_dispatch = cfqd->cfq_quantum;
        }
 
        /*
@@ -2980,30 +2981,20 @@ static void
 cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                       struct request *rq)
 {
-       sector_t sdist;
-       u64 total;
+       sector_t sdist = 0;
+       sector_t n_sec = blk_rq_sectors(rq);
+       if (cfqq->last_request_pos) {
+               if (cfqq->last_request_pos < blk_rq_pos(rq))
+                       sdist = blk_rq_pos(rq) - cfqq->last_request_pos;
+               else
+                       sdist = cfqq->last_request_pos - blk_rq_pos(rq);
+       }
 
-       if (!cfqq->last_request_pos)
-               sdist = 0;
-       else if (cfqq->last_request_pos < blk_rq_pos(rq))
-               sdist = blk_rq_pos(rq) - cfqq->last_request_pos;
+       cfqq->seek_history <<= 1;
+       if (blk_queue_nonrot(cfqd->queue))
+               cfqq->seek_history |= (n_sec < CFQQ_SECT_THR_NONROT);
        else
-               sdist = cfqq->last_request_pos - blk_rq_pos(rq);
-
-       /*
-        * Don't allow the seek distance to get too large from the
-        * odd fragment, pagein, etc
-        */
-       if (cfqq->seek_samples <= 60) /* second&third seek */
-               sdist = min(sdist, (cfqq->seek_mean * 4) + 2*1024*1024);
-       else
-               sdist = min(sdist, (cfqq->seek_mean * 4) + 2*1024*64);
-
-       cfqq->seek_samples = (7*cfqq->seek_samples + 256) / 8;
-       cfqq->seek_total = (7*cfqq->seek_total + (u64)256*sdist) / 8;
-       total = cfqq->seek_total + (cfqq->seek_samples/2);
-       do_div(total, cfqq->seek_samples);
-       cfqq->seek_mean = (sector_t)total;
+               cfqq->seek_history |= (sdist > CFQQ_SEEK_THR);
 }
 
 /*
@@ -3028,8 +3019,7 @@ cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                cfq_mark_cfqq_deep(cfqq);
 
        if (!atomic_read(&cic->ioc->nr_tasks) || !cfqd->cfq_slice_idle ||
-           (!cfq_cfqq_deep(cfqq) && sample_valid(cfqq->seek_samples)
-            && CFQQ_SEEKY(cfqq)))
+           (!cfq_cfqq_deep(cfqq) && CFQQ_SEEKY(cfqq)))
                enable_idle = 0;
        else if (sample_valid(cic->ttime_samples)) {
                if (cic->ttime_mean > cfqd->cfq_slice_idle)
@@ -3215,14 +3205,14 @@ static void cfq_update_hw_tag(struct cfq_data *cfqd)
 {
        struct cfq_queue *cfqq = cfqd->active_queue;
 
-       if (rq_in_driver(cfqd) > cfqd->hw_tag_est_depth)
-               cfqd->hw_tag_est_depth = rq_in_driver(cfqd);
+       if (cfqd->rq_in_driver > cfqd->hw_tag_est_depth)
+               cfqd->hw_tag_est_depth = cfqd->rq_in_driver;
 
        if (cfqd->hw_tag == 1)
                return;
 
        if (cfqd->rq_queued <= CFQ_HW_QUEUE_MIN &&
-           rq_in_driver(cfqd) <= CFQ_HW_QUEUE_MIN)
+           cfqd->rq_in_driver <= CFQ_HW_QUEUE_MIN)
                return;
 
        /*
@@ -3232,7 +3222,7 @@ static void cfq_update_hw_tag(struct cfq_data *cfqd)
         */
        if (cfqq && cfq_cfqq_idle_window(cfqq) &&
            cfqq->dispatched + cfqq->queued[0] + cfqq->queued[1] <
-           CFQ_HW_QUEUE_MIN && rq_in_driver(cfqd) < CFQ_HW_QUEUE_MIN)
+           CFQ_HW_QUEUE_MIN && cfqd->rq_in_driver < CFQ_HW_QUEUE_MIN)
                return;
 
        if (cfqd->hw_tag_samples++ < 50)
@@ -3285,13 +3275,12 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq)
 
        cfq_update_hw_tag(cfqd);
 
-       WARN_ON(!cfqd->rq_in_driver[sync]);
+       WARN_ON(!cfqd->rq_in_driver);
        WARN_ON(!cfqq->dispatched);
-       cfqd->rq_in_driver[sync]--;
+       cfqd->rq_in_driver--;
        cfqq->dispatched--;
 
-       if (cfq_cfqq_sync(cfqq))
-               cfqd->sync_flight--;
+       cfqd->rq_in_flight[cfq_cfqq_sync(cfqq)]--;
 
        if (sync) {
                RQ_CIC(rq)->last_end_request = now;
@@ -3345,7 +3334,7 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq)
                }
        }
 
-       if (!rq_in_driver(cfqd))
+       if (!cfqd->rq_in_driver)
                cfq_schedule_dispatch(cfqd);
 }
 
index 9ad5ccc4c5eeca51408eef4bbfc1da33a7c8d532..ee3a883840f268b1343300ad40368005e2d317dc 100644 (file)
@@ -473,6 +473,15 @@ int elv_merge(struct request_queue *q, struct request **req, struct bio *bio)
        struct request *__rq;
        int ret;
 
+       /*
+        * Levels of merges:
+        *      nomerges:  No merges at all attempted
+        *      noxmerges: Only simple one-hit cache try
+        *      merges:    All merge tries attempted
+        */
+       if (blk_queue_nomerges(q))
+               return ELEVATOR_NO_MERGE;
+
        /*
         * First try one-hit cache.
         */
@@ -484,7 +493,7 @@ int elv_merge(struct request_queue *q, struct request **req, struct bio *bio)
                }
        }
 
-       if (blk_queue_nomerges(q))
+       if (blk_queue_noxmerges(q))
                return ELEVATOR_NO_MERGE;
 
        /*
index 3b20786cbb0d0c5f2ca878fc3736d8cb68e52825..3e50c74ed4a1e5b3c5880d15f7b4025f3e5041af 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a4471e3d3853f19b05ed462c7aef07e5d3fdd01b..33181ad350d5e1be00982cec40f497f0c47aa2ae 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a4fb001d96f1742065c29a7b16e233871b47c3eb..48faf3eba9fb60cf0806d2516a69d1150b6883f0 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 6291904be01e564d7b4433a1d35fbd30144f2774..894a0ff2a94681e9653cf95659cf19823444e2d2 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 4ced54f7a5d97d0ff0b005bf568b0e2aaf72a188..3e6ba99e4053a0824252de17989e79f72193021f 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -133,8 +133,7 @@ acpi_status acpi_ev_initialize_op_regions(void);
 acpi_status
 acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
                               u32 function,
-                              u32 region_offset,
-                              u32 bit_width, acpi_integer * value);
+                              u32 region_offset, u32 bit_width, u64 *value);
 
 acpi_status
 acpi_ev_attach_region(union acpi_operand_object *handler_obj,
index 29ba66d5a7900ea09ebbcbc1716104aabad361b4..f8dd8f250ac4472b1ed92682f1fb3d635a9f37e4 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 36192f142fbb5bdc57997d0600c48284c56878c0..5900f135dc6d93e4bd05d0abbf9ce5e4bea82cba 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 5db9f2916f7c82fa9d3a85166fadda5331f091b9..6df3f8428168e857dc8e20b76a63034b616ee0d2 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -129,18 +129,17 @@ acpi_ex_common_buffer_setup(union acpi_operand_object *obj_desc,
 
 acpi_status
 acpi_ex_write_with_update_rule(union acpi_operand_object *obj_desc,
-                              acpi_integer mask,
-                              acpi_integer field_value,
-                              u32 field_datum_byte_offset);
+                              u64 mask,
+                              u64 field_value, u32 field_datum_byte_offset);
 
 void
-acpi_ex_get_buffer_datum(acpi_integer * datum,
+acpi_ex_get_buffer_datum(u64 *datum,
                         void *buffer,
                         u32 buffer_length,
                         u32 byte_granularity, u32 buffer_offset);
 
 void
-acpi_ex_set_buffer_datum(acpi_integer merged_datum,
+acpi_ex_set_buffer_datum(u64 merged_datum,
                         void *buffer,
                         u32 buffer_length,
                         u32 byte_granularity, u32 buffer_offset);
@@ -168,8 +167,7 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
 
 acpi_status
 acpi_ex_access_region(union acpi_operand_object *obj_desc,
-                     u32 field_datum_byte_offset,
-                     acpi_integer * value, u32 read_write);
+                     u32 field_datum_byte_offset, u64 *value, u32 read_write);
 
 /*
  * exmisc - misc support routines
@@ -193,16 +191,14 @@ acpi_ex_do_concatenate(union acpi_operand_object *obj_desc,
 
 acpi_status
 acpi_ex_do_logical_numeric_op(u16 opcode,
-                             acpi_integer integer0,
-                             acpi_integer integer1, u8 * logical_result);
+                             u64 integer0, u64 integer1, u8 *logical_result);
 
 acpi_status
 acpi_ex_do_logical_op(u16 opcode,
                      union acpi_operand_object *operand0,
-                     union acpi_operand_object *operand1, u8 * logical_result);
+                     union acpi_operand_object *operand1, u8 *logical_result);
 
-acpi_integer
-acpi_ex_do_math_op(u16 opcode, acpi_integer operand0, acpi_integer operand1);
+u64 acpi_ex_do_math_op(u16 opcode, u64 operand0, u64 operand1);
 
 acpi_status acpi_ex_create_mutex(struct acpi_walk_state *walk_state);
 
@@ -278,7 +274,7 @@ acpi_status
 acpi_ex_system_do_notify_op(union acpi_operand_object *value,
                            union acpi_operand_object *obj_desc);
 
-acpi_status acpi_ex_system_do_suspend(acpi_integer time);
+acpi_status acpi_ex_system_do_suspend(u64 time);
 
 acpi_status acpi_ex_system_do_stall(u32 time);
 
@@ -461,9 +457,9 @@ void acpi_ex_acquire_global_lock(u32 rule);
 
 void acpi_ex_release_global_lock(u32 rule);
 
-void acpi_ex_eisa_id_to_string(char *dest, acpi_integer compressed_id);
+void acpi_ex_eisa_id_to_string(char *dest, u64 compressed_id);
 
-void acpi_ex_integer_to_string(char *dest, acpi_integer value);
+void acpi_ex_integer_to_string(char *dest, u64 value);
 
 /*
  * exregion - default op_region handlers
@@ -472,7 +468,7 @@ acpi_status
 acpi_ex_system_memory_space_handler(u32 function,
                                    acpi_physical_address address,
                                    u32 bit_width,
-                                   acpi_integer * value,
+                                   u64 *value,
                                    void *handler_context,
                                    void *region_context);
 
@@ -480,35 +476,35 @@ acpi_status
 acpi_ex_system_io_space_handler(u32 function,
                                acpi_physical_address address,
                                u32 bit_width,
-                               acpi_integer * value,
+                               u64 *value,
                                void *handler_context, void *region_context);
 
 acpi_status
 acpi_ex_pci_config_space_handler(u32 function,
                                 acpi_physical_address address,
                                 u32 bit_width,
-                                acpi_integer * value,
+                                u64 *value,
                                 void *handler_context, void *region_context);
 
 acpi_status
 acpi_ex_cmos_space_handler(u32 function,
                           acpi_physical_address address,
                           u32 bit_width,
-                          acpi_integer * value,
+                          u64 *value,
                           void *handler_context, void *region_context);
 
 acpi_status
 acpi_ex_pci_bar_space_handler(u32 function,
                              acpi_physical_address address,
                              u32 bit_width,
-                             acpi_integer * value,
+                             u64 *value,
                              void *handler_context, void *region_context);
 
 acpi_status
 acpi_ex_embedded_controller_space_handler(u32 function,
                                          acpi_physical_address address,
                                          u32 bit_width,
-                                         acpi_integer * value,
+                                         u64 *value,
                                          void *handler_context,
                                          void *region_context);
 
@@ -516,14 +512,14 @@ acpi_status
 acpi_ex_sm_bus_space_handler(u32 function,
                             acpi_physical_address address,
                             u32 bit_width,
-                            acpi_integer * value,
+                            u64 *value,
                             void *handler_context, void *region_context);
 
 acpi_status
 acpi_ex_data_table_space_handler(u32 function,
                                 acpi_physical_address address,
                                 u32 bit_width,
-                                acpi_integer * value,
+                                u64 *value,
                                 void *handler_context, void *region_context);
 
 #endif                         /* __INTERP_H__ */
index 13cb80caacdeaa83e4b48f9864f18379b4eedc80..24b8faa5c395e7db2100f9cea01568911af8d503 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -374,6 +374,7 @@ union acpi_predefined_info {
 struct acpi_predefined_data {
        char *pathname;
        const union acpi_predefined_info *predefined;
+       union acpi_operand_object *parent_package;
        u32 flags;
        u8 node_flags;
 };
@@ -651,8 +652,7 @@ struct acpi_opcode_info {
 };
 
 union acpi_parse_value {
-       acpi_integer integer;   /* Integer constant (Up to 64 bits) */
-       struct uint64_struct integer64; /* Structure overlay for 2 32-bit Dwords */
+       u64 integer;            /* Integer constant (Up to 64 bits) */
        u32 size;               /* bytelist or field size */
        char *string;           /* NULL terminated string */
        u8 *buffer;             /* buffer or string */
index 7d9ba6e575540216fc4bac2cfc82c95f3aec267f..9894929a2abbc8320f31133f3f68a5f516cc3721 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * MASK_BITS_ABOVE creates a mask starting AT the position and above
  * MASK_BITS_BELOW creates a mask starting one bit BELOW the position
  */
-#define ACPI_MASK_BITS_ABOVE(position)      (~((ACPI_INTEGER_MAX) << ((u32) (position))))
-#define ACPI_MASK_BITS_BELOW(position)      ((ACPI_INTEGER_MAX) << ((u32) (position)))
+#define ACPI_MASK_BITS_ABOVE(position)      (~((ACPI_UINT64_MAX) << ((u32) (position))))
+#define ACPI_MASK_BITS_BELOW(position)      ((ACPI_UINT64_MAX) << ((u32) (position)))
 
 /* Bitfields within ACPI registers */
 
                                                                                        acpi_ut_ptr_exit (ACPI_DEBUG_PARAMETERS, (u8 *) _s); \
                                                                                        return (_s); })
 #define return_VALUE(s)                 ACPI_DO_WHILE0 ({ \
-                                                                                       register acpi_integer _s = (s); \
+                                                                                       register u64 _s = (s); \
                                                                                        acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, _s); \
                                                                                        return (_s); })
 #define return_UINT8(s)                 ACPI_DO_WHILE0 ({ \
                                                                                        register u8 _s = (u8) (s); \
-                                                                                       acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, (acpi_integer) _s); \
+                                                                                       acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, (u64) _s); \
                                                                                        return (_s); })
 #define return_UINT32(s)                ACPI_DO_WHILE0 ({ \
                                                                                        register u32 _s = (u32) (s); \
-                                                                                       acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, (acpi_integer) _s); \
+                                                                                       acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, (u64) _s); \
                                                                                        return (_s); })
 #else                          /* Use original less-safe macros */
 
                                                                                        acpi_ut_ptr_exit (ACPI_DEBUG_PARAMETERS, (u8 *) (s)); \
                                                                                        return((s)); })
 #define return_VALUE(s)                 ACPI_DO_WHILE0 ({ \
-                                                                                       acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, (acpi_integer) (s)); \
+                                                                                       acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, (u64) (s)); \
                                                                                        return((s)); })
 #define return_UINT8(s)                 return_VALUE(s)
 #define return_UINT32(s)                return_VALUE(s)
index 61edb156e8d088e7e320b6af4bb5a72e350aba66..258159cfcdfa224fd8f156e5aec2c599b377554f 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -286,6 +286,17 @@ acpi_status
 acpi_ns_repair_package_list(struct acpi_predefined_data *data,
                            union acpi_operand_object **obj_desc_ptr);
 
+acpi_status
+acpi_ns_repair_null_element(struct acpi_predefined_data *data,
+                           u32 expected_btypes,
+                           u32 package_index,
+                           union acpi_operand_object **return_object_ptr);
+
+void
+acpi_ns_remove_null_elements(struct acpi_predefined_data *data,
+                            u8 package_type,
+                            union acpi_operand_object *obj_desc);
+
 /*
  * nsrepair2 - Return object repair for specific
  * predefined methods/objects
@@ -296,11 +307,6 @@ acpi_ns_complex_repairs(struct acpi_predefined_data *data,
                        acpi_status validate_status,
                        union acpi_operand_object **return_object_ptr);
 
-void
-acpi_ns_remove_null_elements(struct acpi_predefined_data *data,
-                            u8 package_type,
-                            union acpi_operand_object *obj_desc);
-
 /*
  * nssearch - Namespace searching and entry
  */
index 07f6e2ea2ee548f9c5578f13449b4b618aafd7b3..cde18ea82656777131078cca7702db8355855d8f 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -111,7 +111,7 @@ ACPI_OBJECT_COMMON_HEADER};
 
 struct acpi_object_integer {
        ACPI_OBJECT_COMMON_HEADER u8 fill[3];   /* Prevent warning on some compilers */
-       acpi_integer value;
+       u64 value;
 };
 
 /*
index dfdf63327885c9c5e2e2fb898daf1f5a90f1dd1a..8c15ff43f42b34ae639e51234ae2a2df8be187d1 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 22881e8ce22983ab71d11ee9177141c4429a9c2e..d0bb0fd3e57a8d6015784598e4c262e1dc33c3d5 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 57bdaf6ffab1b43e1f91dfb35c04bdc8422db7fe..97116082cb6c58f7fb20c7b1e1523a8864e663de 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index eef5bd7a59faf3fd426e8602c9bc0240fd9a8a99..528bcbaf4ce76180dc434d9ea2e3714794d79686 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 7980a26bad356240038584568b6b0ce404c562fe..161bc0e3d70ad5b460fa87cb80b40ba3b624df82 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 01c76b8ea7bae61c31157c624cad117d37be4c19..8ff3b741df285527ae89729cfc1b38bbe6a58036 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3a451a21a3f99d1446ff6f4eb259e3dda27adfe3..35df755251ce0522907b4dd619f065e073c236e3 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -134,7 +134,7 @@ char *acpi_ut_get_region_name(u8 space_id);
 
 char *acpi_ut_get_event_name(u32 event_id);
 
-char acpi_ut_hex_to_ascii_char(acpi_integer integer, u32 position);
+char acpi_ut_hex_to_ascii_char(u64 integer, u32 position);
 
 u8 acpi_ut_valid_object_type(acpi_object_type type);
 
@@ -279,8 +279,7 @@ acpi_ut_status_exit(u32 line_number,
 void
 acpi_ut_value_exit(u32 line_number,
                   const char *function_name,
-                  const char *module_name,
-                  u32 component_id, acpi_integer value);
+                  const char *module_name, u32 component_id, u64 value);
 
 void
 acpi_ut_ptr_exit(u32 line_number,
@@ -324,7 +323,7 @@ acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node,
 acpi_status
 acpi_ut_evaluate_numeric_object(char *object_name,
                                struct acpi_namespace_node *device_node,
-                               acpi_integer *value);
+                               u64 *value);
 
 acpi_status
 acpi_ut_execute_STA(struct acpi_namespace_node *device_node, u32 *status_flags);
@@ -437,14 +436,12 @@ void acpi_ut_delete_generic_state(union acpi_generic_state *state);
  * utmath
  */
 acpi_status
-acpi_ut_divide(acpi_integer in_dividend,
-              acpi_integer in_divisor,
-              acpi_integer * out_quotient, acpi_integer * out_remainder);
+acpi_ut_divide(u64 in_dividend,
+              u64 in_divisor, u64 *out_quotient, u64 *out_remainder);
 
 acpi_status
-acpi_ut_short_divide(acpi_integer in_dividend,
-                    u32 divisor,
-                    acpi_integer * out_quotient, u32 * out_remainder);
+acpi_ut_short_divide(u64 in_dividend,
+                    u32 divisor, u64 *out_quotient, u32 *out_remainder);
 
 /*
  * utmisc
@@ -474,8 +471,7 @@ acpi_name acpi_ut_repair_name(char *name);
 
 u8 acpi_ut_valid_acpi_char(char character, u32 position);
 
-acpi_status
-acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer);
+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,
index 4940249f252427ef093e2fb93f2d9497c4f07ca6..1f484ba228fc0c63e47402175dd7a9225e062c4a 100644 (file)
@@ -7,7 +7,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 7b070e42b7c5234fd0c11750db5c931384710c0a..0e5798fcbb19d794d6766aa5c097907ddbfc4f75 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 54a225e56a64f33188a8cdd05d31ad157431fb9b..bb13817e0c318b568a6e8d473678e81173adc1a9 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -220,7 +220,7 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info,
                        union acpi_parse_object *arg)
 {
        acpi_status status;
-       acpi_integer position;
+       u64 position;
 
        ACPI_FUNCTION_TRACE_PTR(ds_get_field_names, info);
 
@@ -240,8 +240,8 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info,
                switch (arg->common.aml_opcode) {
                case AML_INT_RESERVEDFIELD_OP:
 
-                       position = (acpi_integer) info->field_bit_position
-                           + (acpi_integer) arg->common.value.size;
+                       position = (u64) info->field_bit_position
+                           + (u64) arg->common.value.size;
 
                        if (position > ACPI_UINT32_MAX) {
                                ACPI_ERROR((AE_INFO,
@@ -305,8 +305,8 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info,
 
                        /* Keep track of bit position for the next field */
 
-                       position = (acpi_integer) info->field_bit_position
-                           + (acpi_integer) arg->common.value.size;
+                       position = (u64) info->field_bit_position
+                           + (u64) arg->common.value.size;
 
                        if (position > ACPI_UINT32_MAX) {
                                ACPI_ERROR((AE_INFO,
index f23fa0be6fc26b27052875f49922da6d34b3b2e5..abe140318a74db1f7f2d51f76bd3f1134a159a73 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index e786f9fd767f3dc0a87715915573b52fd0ddd3bf..721039233aa7704e638805f21015c1ccead2ce78 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 0ba19f84ad82b1e61c8034458c19ada3251fc4a6..cc343b959540a6ecb7631daec5d921a2213fde76 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 9bc1ba07634777ee73315cded8dea9ba68df4add..891e08bf560b8b7f53f537552deb9ff7904c2438 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -684,7 +684,7 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
 
                        case AML_ONES_OP:
 
-                               obj_desc->integer.value = ACPI_INTEGER_MAX;
+                               obj_desc->integer.value = ACPI_UINT64_MAX;
 
                                /* Truncate value if we are executing from a 32-bit ACPI table */
 
index b79978f7bc7172f5ca7e3d60a8fa380576dd009d..bf980cadb1e8345d8b99744841d8f8b0246442b1 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index dfa104102926ffbfa2053b208216c82ecc3f0182..306c62ab2e88ccaacb60546373350c8aad294a97 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f0280856dc0e1040d535a8db1b7f3f28cbcfde21..6b76c486d7840b7a3e7b7ea1303c72f4a0275885 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index b40513dd6a6a90884c16678b4541dd8f84e867d5..140a9d0029599f9103751efce5821368c73cb3b8 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 908645e72f0320477f1f05e83bd43d5a63135cc0..d1e701709dac36b71afd0a1c68b2c936da27acfb 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index e46c821cf57295b7064bd58a333d1692e373451e..050df816416596b61c8e66fcaa75cae6392d9399 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index cd55c774e882c70f168407d01a5fea8c30a4f43b..c1e6f472d435ff6c98b9ebccbc07ef4f85d91ec0 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 0b453467a5a02f2eebcb0cbbf0ce009f444b7495..837de669743a6824c10886ff331718e600ea0d8f 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3d4c4aca11cdabbd64e20c71ee7f5f15eece87a3..fef721917eaf0387aff4d27bcf60e0b41816ec07 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 8f0fac6c436647a546158b944626d3c526139f14..9a3cb7045a3216edc518b8e7d9ac40f14c7a82d1 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 5336d911fbf07c7f6240d72a6691c766c9c1d5ad..98fd210e87b28a31acb9e2cacf1014fa2d03796f 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -329,7 +329,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function)
  *              region_offset       - Where in the region to read or write
  *              bit_width           - Field width in bits (8, 16, 32, or 64)
  *              Value               - Pointer to in or out value, must be
- *                                    full 64-bit acpi_integer
+ *                                    a full 64-bit integer
  *
  * RETURN:      Status
  *
@@ -341,8 +341,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function)
 acpi_status
 acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
                               u32 function,
-                              u32 region_offset,
-                              u32 bit_width, acpi_integer * value)
+                              u32 region_offset, u32 bit_width, u64 *value)
 {
        acpi_status status;
        acpi_adr_space_handler handler;
index ff168052a33261860675a4572c879bf754ab9b16..2e3b0334072f2f67943883097b0a5b8b20e1943a 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -168,7 +168,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
                                void *handler_context, void **region_context)
 {
        acpi_status status = AE_OK;
-       acpi_integer pci_value;
+       u64 pci_value;
        struct acpi_pci_id *pci_id = *region_context;
        union acpi_operand_object *handler_obj;
        struct acpi_namespace_node *parent_node;
index 567b356c85affb780175f5009ebbb12faa0cb8db..8dfbaa96e422ad3f4760133b504c40d90704ebd0 100644 (file)
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 474e2cab603d57cef295791eb22c24fe6d4c76f9..b40757955f9bf802abb4272191dc32ec360c86ff 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 124c157215bfa712bdc700ab56d55285cb8d37c0..5ff32c78ea2db417ba2e303fbb9b401454701508 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c98aa7c2d67c6bbc492e9c842ce8270814e8b0a8..541cbc1544d5d92a5afe113ddb083bc7481b1534 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 46adfa541cbcb20322f570b8e24a2425877b9d3d..7e8b3bedc376993ead990a9f124a92672007ba3c 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -284,7 +284,7 @@ static acpi_status
 acpi_ex_region_read(union acpi_operand_object *obj_desc, u32 length, u8 *buffer)
 {
        acpi_status status;
-       acpi_integer value;
+       u64 value;
        u32 region_offset = 0;
        u32 i;
 
@@ -490,7 +490,11 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
 
        status = acpi_tb_add_table(&table_desc, &table_index);
        if (ACPI_FAILURE(status)) {
-               goto cleanup;
+
+               /* Delete allocated table buffer */
+
+               acpi_tb_delete_table(&table_desc);
+               return_ACPI_STATUS(status);
        }
 
        /*
@@ -533,13 +537,6 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
                                             acpi_gbl_table_handler_context);
        }
 
-      cleanup:
-       if (ACPI_FAILURE(status)) {
-
-               /* Delete allocated table buffer */
-
-               acpi_tb_delete_table(&table_desc);
-       }
        return_ACPI_STATUS(status);
 }
 
index 51d5f224f9fa178509f19cb0821b1b0519452a04..bda7aed0404b6c2ecdf268fdc9b2dc445d0e89b6 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -51,8 +51,7 @@ ACPI_MODULE_NAME("exconvrt")
 
 /* Local prototypes */
 static u32
-acpi_ex_convert_to_ascii(acpi_integer integer,
-                        u16 base, u8 * string, u8 max_length);
+acpi_ex_convert_to_ascii(u64 integer, u16 base, u8 *string, u8 max_length);
 
 /*******************************************************************************
  *
@@ -75,7 +74,7 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
 {
        union acpi_operand_object *return_desc;
        u8 *pointer;
-       acpi_integer result;
+       u64 result;
        u32 i;
        u32 count;
        acpi_status status;
@@ -155,7 +154,7 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
                         * Little endian is used, meaning that the first byte of the buffer
                         * is the LSB of the integer
                         */
-                       result |= (((acpi_integer) pointer[i]) << (i * 8));
+                       result |= (((u64) pointer[i]) << (i * 8));
                }
                break;
 
@@ -285,10 +284,9 @@ acpi_ex_convert_to_buffer(union acpi_operand_object *obj_desc,
  ******************************************************************************/
 
 static u32
-acpi_ex_convert_to_ascii(acpi_integer integer,
-                        u16 base, u8 * string, u8 data_width)
+acpi_ex_convert_to_ascii(u64 integer, u16 base, u8 *string, u8 data_width)
 {
-       acpi_integer digit;
+       u64 digit;
        u32 i;
        u32 j;
        u32 k = 0;
@@ -531,10 +529,9 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
                 * (separated by commas or spaces)
                 */
                for (i = 0; i < obj_desc->buffer.length; i++) {
-                       new_buf += acpi_ex_convert_to_ascii((acpi_integer)
-                                                           obj_desc->buffer.
-                                                           pointer[i], base,
-                                                           new_buf, 1);
+                       new_buf += acpi_ex_convert_to_ascii((u64) obj_desc->
+                                                           buffer.pointer[i],
+                                                           base, new_buf, 1);
                        *new_buf++ = separator; /* each separated by a comma or space */
                }
 
index 02b25d233d994523323e673f3f7eb8e99efb4da4..0aa57d93869878795a8bf22659ceaad8a268618a 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index de3446372ddc04cf4c7aa037703a82fa8d022ae8..d39d438ba1e3468560d24bb991a47ae54e5ac127 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1588a2d660e7ce08d21033620a6b6d10cb666dee..6c79fecbee427505e42d7e4b2b70501d532f9d53 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -130,7 +130,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
                /* Call the region handler for the read */
 
                status = acpi_ex_access_region(obj_desc, 0,
-                                              ACPI_CAST_PTR(acpi_integer,
+                                              ACPI_CAST_PTR(u64,
                                                             buffer_desc->
                                                             buffer.pointer),
                                               function);
@@ -141,7 +141,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
        /*
         * Allocate a buffer for the contents of the field.
         *
-        * If the field is larger than the size of an acpi_integer, create
+        * If the field is larger than the current integer width, create
         * a BUFFER to hold it.  Otherwise, use an INTEGER.  This allows
         * the use of arithmetic operators on the returned value if the
         * field size is equal or smaller than an Integer.
@@ -306,8 +306,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
                 * same buffer)
                 */
                status = acpi_ex_access_region(obj_desc, 0,
-                                              (acpi_integer *) buffer,
-                                              function);
+                                              (u64 *) buffer, function);
                acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
 
                *result_desc = buffer_desc;
index d7b3b418fb45739e82efdc20a6a2477270511842..f68a216168be895b15b1931cabdbc64782d1953b 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -55,11 +55,10 @@ ACPI_MODULE_NAME("exfldio")
 static acpi_status
 acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
                       u32 field_datum_byte_offset,
-                      acpi_integer * value, u32 read_write);
+                      u64 *value, u32 read_write);
 
 static u8
-acpi_ex_register_overflow(union acpi_operand_object *obj_desc,
-                         acpi_integer value);
+acpi_ex_register_overflow(union acpi_operand_object *obj_desc, u64 value);
 
 static acpi_status
 acpi_ex_setup_region(union acpi_operand_object *obj_desc,
@@ -212,7 +211,7 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc,
  *              field_datum_byte_offset - Byte offset of this datum within the
  *                                        parent field
  *              Value                   - Where to store value (must at least
- *                                        the size of acpi_integer)
+ *                                        64 bits)
  *              Function                - Read or Write flag plus other region-
  *                                        dependent flags
  *
@@ -224,8 +223,7 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc,
 
 acpi_status
 acpi_ex_access_region(union acpi_operand_object *obj_desc,
-                     u32 field_datum_byte_offset,
-                     acpi_integer * value, u32 function)
+                     u32 field_datum_byte_offset, u64 *value, u32 function)
 {
        acpi_status status;
        union acpi_operand_object *rgn_desc;
@@ -317,8 +315,7 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc,
  ******************************************************************************/
 
 static u8
-acpi_ex_register_overflow(union acpi_operand_object *obj_desc,
-                         acpi_integer value)
+acpi_ex_register_overflow(union acpi_operand_object *obj_desc, u64 value)
 {
 
        if (obj_desc->common_field.bit_length >= ACPI_INTEGER_BIT_SIZE) {
@@ -329,7 +326,7 @@ acpi_ex_register_overflow(union acpi_operand_object *obj_desc,
                return (FALSE);
        }
 
-       if (value >= ((acpi_integer) 1 << obj_desc->common_field.bit_length)) {
+       if (value >= ((u64) 1 << obj_desc->common_field.bit_length)) {
                /*
                 * The Value is larger than the maximum value that can fit into
                 * the register.
@@ -362,11 +359,10 @@ acpi_ex_register_overflow(union acpi_operand_object *obj_desc,
 
 static acpi_status
 acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
-                      u32 field_datum_byte_offset,
-                      acpi_integer * value, u32 read_write)
+                      u32 field_datum_byte_offset, u64 *value, u32 read_write)
 {
        acpi_status status;
-       acpi_integer local_value;
+       u64 local_value;
 
        ACPI_FUNCTION_TRACE_U32(ex_field_datum_io, field_datum_byte_offset);
 
@@ -439,8 +435,8 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
                 * the register
                 */
                if (acpi_ex_register_overflow(obj_desc->bank_field.bank_obj,
-                                             (acpi_integer) obj_desc->
-                                             bank_field.value)) {
+                                             (u64) obj_desc->bank_field.
+                                             value)) {
                        return_ACPI_STATUS(AE_AML_REGISTER_LIMIT);
                }
 
@@ -481,8 +477,8 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
                 * the register
                 */
                if (acpi_ex_register_overflow(obj_desc->index_field.index_obj,
-                                             (acpi_integer) obj_desc->
-                                             index_field.value)) {
+                                             (u64) obj_desc->index_field.
+                                             value)) {
                        return_ACPI_STATUS(AE_AML_REGISTER_LIMIT);
                }
 
@@ -512,7 +508,7 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
                        status =
                            acpi_ex_extract_from_field(obj_desc->index_field.
                                                       data_obj, value,
-                                                      sizeof(acpi_integer));
+                                                      sizeof(u64));
                } else {
                        /* Write the datum to the data_register */
 
@@ -523,7 +519,7 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
                        status =
                            acpi_ex_insert_into_field(obj_desc->index_field.
                                                      data_obj, value,
-                                                     sizeof(acpi_integer));
+                                                     sizeof(u64));
                }
                break;
 
@@ -571,13 +567,12 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
 
 acpi_status
 acpi_ex_write_with_update_rule(union acpi_operand_object *obj_desc,
-                              acpi_integer mask,
-                              acpi_integer field_value,
-                              u32 field_datum_byte_offset)
+                              u64 mask,
+                              u64 field_value, u32 field_datum_byte_offset)
 {
        acpi_status status = AE_OK;
-       acpi_integer merged_value;
-       acpi_integer current_value;
+       u64 merged_value;
+       u64 current_value;
 
        ACPI_FUNCTION_TRACE_U32(ex_write_with_update_rule, mask);
 
@@ -587,7 +582,7 @@ acpi_ex_write_with_update_rule(union acpi_operand_object *obj_desc,
 
        /* If the mask is all ones, we don't need to worry about the update rule */
 
-       if (mask != ACPI_INTEGER_MAX) {
+       if (mask != ACPI_UINT64_MAX) {
 
                /* Decode the update rule */
 
@@ -678,8 +673,8 @@ acpi_ex_extract_from_field(union acpi_operand_object *obj_desc,
                           void *buffer, u32 buffer_length)
 {
        acpi_status status;
-       acpi_integer raw_datum;
-       acpi_integer merged_datum;
+       u64 raw_datum;
+       u64 merged_datum;
        u32 field_offset = 0;
        u32 buffer_offset = 0;
        u32 buffer_tail_bits;
@@ -804,10 +799,10 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
                          void *buffer, u32 buffer_length)
 {
        acpi_status status;
-       acpi_integer mask;
-       acpi_integer width_mask;
-       acpi_integer merged_datum;
-       acpi_integer raw_datum = 0;
+       u64 mask;
+       u64 width_mask;
+       u64 merged_datum;
+       u64 raw_datum = 0;
        u32 field_offset = 0;
        u32 buffer_offset = 0;
        u32 buffer_tail_bits;
@@ -855,7 +850,7 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
         * shift operator
         */
        if (obj_desc->common_field.access_bit_width == ACPI_INTEGER_BIT_SIZE) {
-               width_mask = ACPI_INTEGER_MAX;
+               width_mask = ACPI_UINT64_MAX;
        } else {
                width_mask =
                    ACPI_MASK_BITS_ABOVE(obj_desc->common_field.
index 998eac32993789b28cff471fc30d5bc345907709..c5bb1eeed2dff2486636c4c5736093a9d06d9299 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -409,8 +409,7 @@ acpi_ex_do_concatenate(union acpi_operand_object *operand0,
  *
  ******************************************************************************/
 
-acpi_integer
-acpi_ex_do_math_op(u16 opcode, acpi_integer integer0, acpi_integer integer1)
+u64 acpi_ex_do_math_op(u16 opcode, u64 integer0, u64 integer1)
 {
 
        ACPI_FUNCTION_ENTRY();
@@ -498,8 +497,7 @@ acpi_ex_do_math_op(u16 opcode, acpi_integer integer0, acpi_integer integer1)
 
 acpi_status
 acpi_ex_do_logical_numeric_op(u16 opcode,
-                             acpi_integer integer0,
-                             acpi_integer integer1, u8 * logical_result)
+                             u64 integer0, u64 integer1, u8 *logical_result)
 {
        acpi_status status = AE_OK;
        u8 local_result = FALSE;
@@ -564,8 +562,8 @@ acpi_ex_do_logical_op(u16 opcode,
                      union acpi_operand_object *operand1, u8 * logical_result)
 {
        union acpi_operand_object *local_operand1 = operand1;
-       acpi_integer integer0;
-       acpi_integer integer1;
+       u64 integer0;
+       u64 integer1;
        u32 length0;
        u32 length1;
        acpi_status status = AE_OK;
index 3c456bd575d0398224fe1ce600da19a000156c48..cc8a10268f6832a18386da38b3abab00f32bd2b0 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ffdae122d94af6e365aca484d95678b77d81e759..679f308c5a89826e2c1002bd7a4ec9c7fc565074 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 752fe48b2d2004129cc91725bfb4cf79f78deed8..99adbab5acbf4c854e86c252b8da33e607253b3f 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -261,8 +261,8 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state)
        union acpi_operand_object *return_desc2 = NULL;
        u32 temp32;
        u32 i;
-       acpi_integer power_of_ten;
-       acpi_integer digit;
+       u64 power_of_ten;
+       u64 digit;
 
        ACPI_FUNCTION_TRACE_STR(ex_opcode_1A_1T_1R,
                                acpi_ps_get_opcode_name(walk_state->opcode));
@@ -362,7 +362,7 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state)
                                /* Sum the digit into the result with the current power of 10 */
 
                                return_desc->integer.value +=
-                                   (((acpi_integer) temp32) * power_of_ten);
+                                   (((u64) temp32) * power_of_ten);
 
                                /* Shift to next BCD digit */
 
@@ -392,7 +392,7 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state)
                                 * remainder from above
                                 */
                                return_desc->integer.value |=
-                                   (((acpi_integer) temp32) << ACPI_MUL_4(i));
+                                   (((u64) temp32) << ACPI_MUL_4(i));
                        }
 
                        /* Overflow if there is any data left in Digit */
@@ -439,7 +439,7 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state)
 
                        /* The object exists in the namespace, return TRUE */
 
-                       return_desc->integer.value = ACPI_INTEGER_MAX;
+                       return_desc->integer.value = ACPI_UINT64_MAX;
                        goto cleanup;
 
                default:
@@ -589,7 +589,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
        union acpi_operand_object *return_desc = NULL;
        acpi_status status = AE_OK;
        u32 type;
-       acpi_integer value;
+       u64 value;
 
        ACPI_FUNCTION_TRACE_STR(ex_opcode_1A_0T_1R,
                                acpi_ps_get_opcode_name(walk_state->opcode));
@@ -610,7 +610,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
                 * return_desc->Integer.Value is initially == 0 (FALSE) from above.
                 */
                if (!operand[0]->integer.value) {
-                       return_desc->integer.value = ACPI_INTEGER_MAX;
+                       return_desc->integer.value = ACPI_UINT64_MAX;
                }
                break;
 
index 85d95c92dfd3d72d3c35659e5fb64a54111708ed..22841bbbe63ca073545add2473eaf1abce51dce3 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -282,7 +282,7 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state)
 {
        union acpi_operand_object **operand = &walk_state->operands[0];
        union acpi_operand_object *return_desc = NULL;
-       acpi_integer index;
+       u64 index;
        acpi_status status = AE_OK;
        acpi_size length;
 
@@ -584,7 +584,7 @@ acpi_status acpi_ex_opcode_2A_0T_1R(struct acpi_walk_state *walk_state)
         * Default is FALSE (zero)
         */
        if (logical_result) {
-               return_desc->integer.value = ACPI_INTEGER_MAX;
+               return_desc->integer.value = ACPI_UINT64_MAX;
        }
 
       cleanup:
index 253f9e122584db597c9e85cde12914fab6f43079..8bb1012ef44e4c04fe9b47bd062cedea6aa25e7e 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -148,7 +148,7 @@ acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state)
        union acpi_operand_object *return_desc = NULL;
        char *buffer = NULL;
        acpi_status status = AE_OK;
-       acpi_integer index;
+       u64 index;
        acpi_size length;
 
        ACPI_FUNCTION_TRACE_STR(ex_opcode_3A_1T_1R,
index 295542e6bd51f21d4318b79de6bd93f0ac42bf03..f256b6a25f2e646fb7e4a0e31570fa0838de5820 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -218,7 +218,7 @@ acpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state * walk_state)
        union acpi_operand_object **operand = &walk_state->operands[0];
        union acpi_operand_object *return_desc = NULL;
        acpi_status status = AE_OK;
-       acpi_integer index;
+       u64 index;
        union acpi_operand_object *this_element;
 
        ACPI_FUNCTION_TRACE_STR(ex_opcode_6A_0T_1R,
@@ -253,9 +253,9 @@ acpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state * walk_state)
                }
 
                /* Create an integer for the return value */
-               /* Default return value is ACPI_INTEGER_MAX if no match found */
+               /* Default return value is ACPI_UINT64_MAX if no match found */
 
-               return_desc = acpi_ut_create_integer_object(ACPI_INTEGER_MAX);
+               return_desc = acpi_ut_create_integer_object(ACPI_UINT64_MAX);
                if (!return_desc) {
                        status = AE_NO_MEMORY;
                        goto cleanup;
@@ -270,7 +270,7 @@ acpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state * walk_state)
                 *
                 * Upon finding a match, the loop will terminate via "break" at
                 * the bottom.  If it terminates "normally", match_value will be
-                * ACPI_INTEGER_MAX (Ones) (its initial value) indicating that no
+                * ACPI_UINT64_MAX (Ones) (its initial value) indicating that no
                 * match was found.
                 */
                for (; index < operand[0]->package.count; index++) {
index 52fec07064f0be7581aa72160d829b521959bfbe..edf62bf5b266a1c83f7175eb6f9ba503ebd74d52 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 2bd83ac57c3ae5030dab9bf17150a7db0442fda0..486b2e5661b692f6d03d0c4c67680d3f90c06669 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -70,7 +70,7 @@ acpi_status
 acpi_ex_system_memory_space_handler(u32 function,
                                    acpi_physical_address address,
                                    u32 bit_width,
-                                   acpi_integer * value,
+                                   u64 *value,
                                    void *handler_context, void *region_context)
 {
        acpi_status status = AE_OK;
@@ -115,8 +115,7 @@ acpi_ex_system_memory_space_handler(u32 function,
         * Hardware does not support non-aligned data transfers, we must verify
         * the request.
         */
-       (void)acpi_ut_short_divide((acpi_integer) address, length, NULL,
-                                  &remainder);
+       (void)acpi_ut_short_divide((u64) address, length, NULL, &remainder);
        if (remainder != 0) {
                return_ACPI_STATUS(AE_AML_ALIGNMENT);
        }
@@ -128,10 +127,9 @@ acpi_ex_system_memory_space_handler(u32 function,
         *    2) Address beyond the current mapping?
         */
        if ((address < mem_info->mapped_physical_address) ||
-           (((acpi_integer) address + length) > ((acpi_integer)
-                                                 mem_info->
-                                                 mapped_physical_address +
-                                                 mem_info->mapped_length))) {
+           (((u64) address + length) > ((u64)
+                                        mem_info->mapped_physical_address +
+                                        mem_info->mapped_length))) {
                /*
                 * The request cannot be resolved by the current memory mapping;
                 * Delete the existing mapping and create a new one.
@@ -193,8 +191,7 @@ acpi_ex_system_memory_space_handler(u32 function,
         * access
         */
        logical_addr_ptr = mem_info->mapped_logical_address +
-           ((acpi_integer) address -
-            (acpi_integer) mem_info->mapped_physical_address);
+           ((u64) address - (u64) mem_info->mapped_physical_address);
 
        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                          "System-Memory (width %d) R/W %d Address=%8.8X%8.8X\n",
@@ -215,19 +212,19 @@ acpi_ex_system_memory_space_handler(u32 function,
                *value = 0;
                switch (bit_width) {
                case 8:
-                       *value = (acpi_integer) ACPI_GET8(logical_addr_ptr);
+                       *value = (u64) ACPI_GET8(logical_addr_ptr);
                        break;
 
                case 16:
-                       *value = (acpi_integer) ACPI_GET16(logical_addr_ptr);
+                       *value = (u64) ACPI_GET16(logical_addr_ptr);
                        break;
 
                case 32:
-                       *value = (acpi_integer) ACPI_GET32(logical_addr_ptr);
+                       *value = (u64) ACPI_GET32(logical_addr_ptr);
                        break;
 
                case 64:
-                       *value = (acpi_integer) ACPI_GET64(logical_addr_ptr);
+                       *value = (u64) ACPI_GET64(logical_addr_ptr);
                        break;
 
                default:
@@ -291,7 +288,7 @@ acpi_status
 acpi_ex_system_io_space_handler(u32 function,
                                acpi_physical_address address,
                                u32 bit_width,
-                               acpi_integer * value,
+                               u64 *value,
                                void *handler_context, void *region_context)
 {
        acpi_status status = AE_OK;
@@ -350,7 +347,7 @@ acpi_status
 acpi_ex_pci_config_space_handler(u32 function,
                                 acpi_physical_address address,
                                 u32 bit_width,
-                                acpi_integer * value,
+                                u64 *value,
                                 void *handler_context, void *region_context)
 {
        acpi_status status = AE_OK;
@@ -425,7 +422,7 @@ acpi_status
 acpi_ex_cmos_space_handler(u32 function,
                           acpi_physical_address address,
                           u32 bit_width,
-                          acpi_integer * value,
+                          u64 *value,
                           void *handler_context, void *region_context)
 {
        acpi_status status = AE_OK;
@@ -457,7 +454,7 @@ acpi_status
 acpi_ex_pci_bar_space_handler(u32 function,
                              acpi_physical_address address,
                              u32 bit_width,
-                             acpi_integer * value,
+                             u64 *value,
                              void *handler_context, void *region_context)
 {
        acpi_status status = AE_OK;
@@ -489,7 +486,7 @@ acpi_status
 acpi_ex_data_table_space_handler(u32 function,
                                 acpi_physical_address address,
                                 u32 bit_width,
-                                acpi_integer * value,
+                                u64 *value,
                                 void *handler_context, void *region_context)
 {
        ACPI_FUNCTION_TRACE(ex_data_table_space_handler);
index 607958ff467c34f35bf4ef8cde96c4161dbcf561..fdc1b27999ef2e558c81da7a968d779901a3fd5f 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c93b54ce7f787dbecbc5359e165e13c6e8b1eb11..fdd6a7079b975f5e1deed99226dbc5cc25ce219b 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 5c729a9e913107783b4f91e16f510b97dbc02b0d..c5ecd615f145bea2ad3e4c4781254ff50a13ff89 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 6efd07a4f779c5975b864eb81989f60a9f84019f..702b9ecfd44b6ebad0291f7e2c4ce63084f7756d 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 608e838d537e38f451586fead9526ac32bf9548c..d4af684620ca9e8307785518d49b793fb059c560 100644 (file)
@@ -7,7 +7,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 257706e7734f786dbe8e8d760283ef2751859838..e972b667b09b8c7b4874f80032ecd90e6526b128 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3d00b9357233a56ee0d4ff00f96cbd54c7b2560a..e11b6cb42a573dc69a33bd88a9eb358d078a8777 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -193,7 +193,7 @@ acpi_status acpi_ex_system_do_stall(u32 how_long)
  *
  ******************************************************************************/
 
-acpi_status acpi_ex_system_do_suspend(acpi_integer how_long)
+acpi_status acpi_ex_system_do_suspend(u64 how_long)
 {
        ACPI_FUNCTION_ENTRY();
 
index 7d41f99f70522b4683803c84485b74c081da2724..74c24d517f81768a6a00418db71c9f93be335b2e 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -67,7 +67,7 @@
 ACPI_MODULE_NAME("exutils")
 
 /* Local prototypes */
-static u32 acpi_ex_digits_needed(acpi_integer value, u32 base);
+static u32 acpi_ex_digits_needed(u64 value, u32 base);
 
 #ifndef ACPI_NO_METHOD_EXECUTION
 /*******************************************************************************
@@ -230,7 +230,7 @@ void acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc)
                 * We are running a method that exists in a 32-bit ACPI table.
                 * Truncate the value to 32 bits by zeroing out the upper 32-bit field
                 */
-               obj_desc->integer.value &= (acpi_integer) ACPI_UINT32_MAX;
+               obj_desc->integer.value &= (u64) ACPI_UINT32_MAX;
        }
 }
 
@@ -327,14 +327,14 @@ void acpi_ex_release_global_lock(u32 field_flags)
  *
  ******************************************************************************/
 
-static u32 acpi_ex_digits_needed(acpi_integer value, u32 base)
+static u32 acpi_ex_digits_needed(u64 value, u32 base)
 {
        u32 num_digits;
-       acpi_integer current_value;
+       u64 current_value;
 
        ACPI_FUNCTION_TRACE(ex_digits_needed);
 
-       /* acpi_integer is unsigned, so we don't worry about a '-' prefix */
+       /* u64 is unsigned, so we don't worry about a '-' prefix */
 
        if (value == 0) {
                return_UINT32(1);
@@ -370,7 +370,7 @@ static u32 acpi_ex_digits_needed(acpi_integer value, u32 base)
  *
  ******************************************************************************/
 
-void acpi_ex_eisa_id_to_string(char *out_string, acpi_integer compressed_id)
+void acpi_ex_eisa_id_to_string(char *out_string, u64 compressed_id)
 {
        u32 swapped_id;
 
@@ -394,10 +394,10 @@ void acpi_ex_eisa_id_to_string(char *out_string, acpi_integer compressed_id)
            (char)(0x40 + (((unsigned long)swapped_id >> 26) & 0x1F));
        out_string[1] = (char)(0x40 + ((swapped_id >> 21) & 0x1F));
        out_string[2] = (char)(0x40 + ((swapped_id >> 16) & 0x1F));
-       out_string[3] = acpi_ut_hex_to_ascii_char((acpi_integer)swapped_id, 12);
-       out_string[4] = acpi_ut_hex_to_ascii_char((acpi_integer)swapped_id, 8);
-       out_string[5] = acpi_ut_hex_to_ascii_char((acpi_integer)swapped_id, 4);
-       out_string[6] = acpi_ut_hex_to_ascii_char((acpi_integer)swapped_id, 0);
+       out_string[3] = acpi_ut_hex_to_ascii_char((u64) swapped_id, 12);
+       out_string[4] = acpi_ut_hex_to_ascii_char((u64) swapped_id, 8);
+       out_string[5] = acpi_ut_hex_to_ascii_char((u64) swapped_id, 4);
+       out_string[6] = acpi_ut_hex_to_ascii_char((u64) swapped_id, 0);
        out_string[7] = 0;
 }
 
@@ -418,7 +418,7 @@ void acpi_ex_eisa_id_to_string(char *out_string, acpi_integer compressed_id)
  *
  ******************************************************************************/
 
-void acpi_ex_integer_to_string(char *out_string, acpi_integer value)
+void acpi_ex_integer_to_string(char *out_string, u64 value)
 {
        u32 count;
        u32 digits_needed;
index 9af361a191e7344c0c035514bbf27cae44cf7d34..679a112a7d2692b140776ec44554288b1e2557ca 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c28c41b3180bc585dd182aa983cda8abc46ba419..bd72319a38f00fa9357bf76a01976b792e574a01 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -224,7 +224,7 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
 
        status = acpi_hw_read(&in_byte, &gpe_register_info->status_address);
        if (ACPI_FAILURE(status)) {
-               goto unlock_and_exit;
+               return (status);
        }
 
        if (register_bit & in_byte) {
@@ -234,9 +234,7 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
        /* Set return value */
 
        (*event_status) = local_event_status;
-
-      unlock_and_exit:
-       return (status);
+       return (AE_OK);
 }
 
 /******************************************************************************
index 15c9ed2be85326f7fa9bd9d72cdcd70eefed9469..ec7fc227b33fbb0edc996428bb238e987f245c1d 100644 (file)
@@ -7,7 +7,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index cc22f9a585b094fba931e775678661ce829ca21e..5e6d4dbb80243cd34fc5105d507e7c0505fa0891 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 6b282e85d039553a60e507d8241b36ea78cecd2e..1ef8e0bb250bd0dccbedd533e4229fedcb739086 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -140,7 +140,7 @@ acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed)
 {
        acpi_status status;
        u32 delta_ticks;
-       acpi_integer quotient;
+       u64 quotient;
 
        ACPI_FUNCTION_TRACE(acpi_get_timer_duration);
 
index ec33f270c5b7e670d30e77388527786ec747d5fd..e26c17d4b716e254e084b06c16a5fe61bdf2d787 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2009, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 647c7b6e675616a13fbfd16f5a368a620bf3b9ec..50cc3be77724ce53eb3f611401f08bbe3b3a59b3 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d622ba770000f0e22e836c5d49f2edd6d96bd6b4..aa2b80132d0a88d37e8781d6aa7955a539846645 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 8a58a1b85aa097cd34d5204c6ef1b0dbc043f7df..982269c1fa48ca0b5253cfefc929b039faa2ab9f 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index e37836e27e29eb3a2816696fbfb7c5da43b04999..0689d36638d994c866f4b83c3187752e1dffa858 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 36be7f0e97ec00ec66b70fa55da470de62518e51..d2a97921e249e87472966c2981fb9af12ef698dd 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index af9fe91037340ff1e404ffdc521881da8e65bf58..f52829cc294b2fd8abc5d45114ccceea4ab233be 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 4f8abac231d24f3474a8deeaed1c8fd91cacf9b2..9bd6f050f299ef55b545dac56a890d8f3219bc18 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a7234e60e9858c29fbf80cd10bf06a649ee9e898..df18be94fefe9e6753c6050b1964ee851298f7b1 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 8f9a4875ce26708ae06b17a5f637b43a52964537..9593724516353dcdc2bb45653c6d0a8173d9847d 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 60f3af08d28c3955fdee04607e99ce95befda017..41a9213dd5af638fb7dd179d86e9b56f4a1ce9fe 100644 (file)
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 662a4bd5b621888f48bfad4c5ab7a26fa1212084..27cda52c76bcf1a81d7550cd4fae01f5d4c3d414 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d34fa59548f737cd38f1ebc3a242f3563fe3919d..7096bcda0c723b2317affede650241fcbada6e9c 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -231,6 +231,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
         * Note: Package may have been newly created by call above.
         */
        if ((*return_object_ptr)->common.type == ACPI_TYPE_PACKAGE) {
+               data->parent_package = *return_object_ptr;
                status = acpi_ns_check_package(data, return_object_ptr);
                if (ACPI_FAILURE(status)) {
                        goto exit;
@@ -710,6 +711,7 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
        for (i = 0; i < count; i++) {
                sub_package = *elements;
                sub_elements = sub_package->package.elements;
+               data->parent_package = sub_package;
 
                /* Each sub-object must be of type Package */
 
@@ -721,6 +723,7 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
 
                /* Examine the different types of expected sub-packages */
 
+               data->parent_package = sub_package;
                switch (package->ret_info.type) {
                case ACPI_PTYPE2:
                case ACPI_PTYPE2_PKG_COUNT:
@@ -800,7 +803,7 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
 
                        /*
                         * First element is the (Integer) count of elements, including
-                        * the count field.
+                        * the count field (the ACPI name is num_elements)
                         */
                        status = acpi_ns_check_object_type(data, sub_elements,
                                                           ACPI_RTYPE_INTEGER,
@@ -822,6 +825,16 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
                                expected_count = package->ret_info.count1;
                                goto package_too_small;
                        }
+                       if (expected_count == 0) {
+                               /*
+                                * Either the num_entries element was originally zero or it was
+                                * a NULL element and repaired to an Integer of value zero.
+                                * In either case, repair it by setting num_entries to be the
+                                * actual size of the subpackage.
+                                */
+                               expected_count = sub_package->package.count;
+                               (*sub_elements)->integer.value = expected_count;
+                       }
 
                        /* Check the type of each sub-package element */
 
@@ -945,10 +958,18 @@ acpi_ns_check_object_type(struct acpi_predefined_data *data,
        char type_buffer[48];   /* Room for 5 types */
 
        /*
-        * If we get a NULL return_object here, it is a NULL package element,
-        * and this is always an error.
+        * If we get a NULL return_object here, it is a NULL package element.
+        * Since all extraneous NULL package elements were removed earlier by a
+        * call to acpi_ns_remove_null_elements, this is an unexpected NULL element.
+        * We will attempt to repair it.
         */
        if (!return_object) {
+               status = acpi_ns_repair_null_element(data, expected_btypes,
+                                                    package_index,
+                                                    return_object_ptr);
+               if (ACPI_SUCCESS(status)) {
+                       return (AE_OK); /* Repair was successful */
+               }
                goto type_error_exit;
        }
 
@@ -1000,27 +1021,25 @@ acpi_ns_check_object_type(struct acpi_predefined_data *data,
 
        /* Is the object one of the expected types? */
 
-       if (!(return_btype & expected_btypes)) {
+       if (return_btype & expected_btypes) {
 
-               /* Type mismatch -- attempt repair of the returned object */
+               /* For reference objects, check that the reference type is correct */
 
-               status = acpi_ns_repair_object(data, expected_btypes,
-                                              package_index,
-                                              return_object_ptr);
-               if (ACPI_SUCCESS(status)) {
-                       return (AE_OK); /* Repair was successful */
+               if (return_object->common.type == ACPI_TYPE_LOCAL_REFERENCE) {
+                       status = acpi_ns_check_reference(data, return_object);
                }
-               goto type_error_exit;
+
+               return (status);
        }
 
-       /* For reference objects, check that the reference type is correct */
+       /* Type mismatch -- attempt repair of the returned object */
 
-       if (return_object->common.type == ACPI_TYPE_LOCAL_REFERENCE) {
-               status = acpi_ns_check_reference(data, return_object);
+       status = acpi_ns_repair_object(data, expected_btypes,
+                                      package_index, return_object_ptr);
+       if (ACPI_SUCCESS(status)) {
+               return (AE_OK); /* Repair was successful */
        }
 
-       return (status);
-
       type_error_exit:
 
        /* Create a string with all expected types for this predefined object */
index 4fd1bdb056b2ffa496514b0a422c82aef36c35c7..d4be37751be43222a70e9ac8a99da60bad591373 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2009, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -45,6 +45,7 @@
 #include "accommon.h"
 #include "acnamesp.h"
 #include "acinterp.h"
+#include "acpredef.h"
 
 #define _COMPONENT          ACPI_NAMESPACE
 ACPI_MODULE_NAME("nsrepair")
@@ -71,6 +72,12 @@ ACPI_MODULE_NAME("nsrepair")
  * Buffer  -> Package of Integers
  * Package -> Package of one Package
  *
+ * Additional possible repairs:
+ *
+ * Optional/unnecessary NULL package elements removed
+ * Required package elements that are NULL replaced by Integer/String/Buffer
+ * Incorrect standalone package wrapped with required outer package
+ *
  ******************************************************************************/
 /* Local prototypes */
 static acpi_status
@@ -504,6 +511,172 @@ acpi_ns_convert_to_package(union acpi_operand_object *original_object,
        return (AE_OK);
 }
 
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ns_repair_null_element
+ *
+ * PARAMETERS:  Data                - Pointer to validation data structure
+ *              expected_btypes     - Object types expected
+ *              package_index       - Index of object within parent package (if
+ *                                    applicable - ACPI_NOT_PACKAGE_ELEMENT
+ *                                    otherwise)
+ *              return_object_ptr   - Pointer to the object returned from the
+ *                                    evaluation of a method or object
+ *
+ * RETURN:      Status. AE_OK if repair was successful.
+ *
+ * DESCRIPTION: Attempt to repair a NULL element of a returned Package object.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_repair_null_element(struct acpi_predefined_data *data,
+                           u32 expected_btypes,
+                           u32 package_index,
+                           union acpi_operand_object **return_object_ptr)
+{
+       union acpi_operand_object *return_object = *return_object_ptr;
+       union acpi_operand_object *new_object;
+
+       ACPI_FUNCTION_NAME(ns_repair_null_element);
+
+       /* No repair needed if return object is non-NULL */
+
+       if (return_object) {
+               return (AE_OK);
+       }
+
+       /*
+        * Attempt to repair a NULL element of a Package object. This applies to
+        * predefined names that return a fixed-length package and each element
+        * is required. It does not apply to variable-length packages where NULL
+        * elements are allowed, especially at the end of the package.
+        */
+       if (expected_btypes & ACPI_RTYPE_INTEGER) {
+
+               /* Need an Integer - create a zero-value integer */
+
+               new_object = acpi_ut_create_integer_object(0);
+       } else if (expected_btypes & ACPI_RTYPE_STRING) {
+
+               /* Need a String - create a NULL string */
+
+               new_object = acpi_ut_create_string_object(0);
+       } else if (expected_btypes & ACPI_RTYPE_BUFFER) {
+
+               /* Need a Buffer - create a zero-length buffer */
+
+               new_object = acpi_ut_create_buffer_object(0);
+       } else {
+               /* Error for all other expected types */
+
+               return (AE_AML_OPERAND_TYPE);
+       }
+
+       if (!new_object) {
+               return (AE_NO_MEMORY);
+       }
+
+       /* Set the reference count according to the parent Package object */
+
+       new_object->common.reference_count =
+           data->parent_package->common.reference_count;
+
+       ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
+                         "%s: Converted NULL package element to expected %s at index %u\n",
+                         data->pathname,
+                         acpi_ut_get_object_type_name(new_object),
+                         package_index));
+
+       *return_object_ptr = new_object;
+       data->flags |= ACPI_OBJECT_REPAIRED;
+       return (AE_OK);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_ns_remove_null_elements
+ *
+ * PARAMETERS:  Data                - Pointer to validation data structure
+ *              package_type        - An acpi_return_package_types value
+ *              obj_desc            - A Package object
+ *
+ * RETURN:      None.
+ *
+ * DESCRIPTION: Remove all NULL package elements from packages that contain
+ *              a variable number of sub-packages. For these types of
+ *              packages, NULL elements can be safely removed.
+ *
+ *****************************************************************************/
+
+void
+acpi_ns_remove_null_elements(struct acpi_predefined_data *data,
+                            u8 package_type,
+                            union acpi_operand_object *obj_desc)
+{
+       union acpi_operand_object **source;
+       union acpi_operand_object **dest;
+       u32 count;
+       u32 new_count;
+       u32 i;
+
+       ACPI_FUNCTION_NAME(ns_remove_null_elements);
+
+       /*
+        * PTYPE1 packages contain no subpackages.
+        * PTYPE2 packages contain a variable number of sub-packages. We can
+        * safely remove all NULL elements from the PTYPE2 packages.
+        */
+       switch (package_type) {
+       case ACPI_PTYPE1_FIXED:
+       case ACPI_PTYPE1_VAR:
+       case ACPI_PTYPE1_OPTION:
+               return;
+
+       case ACPI_PTYPE2:
+       case ACPI_PTYPE2_COUNT:
+       case ACPI_PTYPE2_PKG_COUNT:
+       case ACPI_PTYPE2_FIXED:
+       case ACPI_PTYPE2_MIN:
+       case ACPI_PTYPE2_REV_FIXED:
+               break;
+
+       default:
+               return;
+       }
+
+       count = obj_desc->package.count;
+       new_count = count;
+
+       source = obj_desc->package.elements;
+       dest = source;
+
+       /* Examine all elements of the package object, remove nulls */
+
+       for (i = 0; i < count; i++) {
+               if (!*source) {
+                       new_count--;
+               } else {
+                       *dest = *source;
+                       dest++;
+               }
+               source++;
+       }
+
+       /* Update parent package if any null elements were removed */
+
+       if (new_count < count) {
+               ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
+                                 "%s: Found and removed %u NULL elements\n",
+                                 data->pathname, (count - new_count)));
+
+               /* NULL terminate list and update the package count */
+
+               *dest = NULL;
+               obj_desc->package.count = new_count;
+       }
+}
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ns_repair_package_list
index f13691c1cca54996097e3ada48b792acf70708ce..61bd0f6755d222ac32dc6703e3f4c9dd8a66a372 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2009, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -45,7 +45,6 @@
 #include <acpi/acpi.h>
 #include "accommon.h"
 #include "acnamesp.h"
-#include "acpredef.h"
 
 #define _COMPONENT          ACPI_NAMESPACE
 ACPI_MODULE_NAME("nsrepair2")
@@ -93,7 +92,7 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data,
                          u32 sort_index,
                          u8 sort_direction, char *sort_key_name);
 
-static acpi_status
+static void
 acpi_ns_sort_list(union acpi_operand_object **elements,
                  u32 count, u32 index, u8 sort_direction);
 
@@ -443,7 +442,6 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data,
        union acpi_operand_object *obj_desc;
        u32 i;
        u32 previous_value;
-       acpi_status status;
 
        ACPI_FUNCTION_NAME(ns_check_sorted_list);
 
@@ -494,19 +492,15 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data,
 
                /*
                 * The list must be sorted in the specified order. If we detect a
-                * discrepancy, issue a warning and sort the entire list
+                * discrepancy, sort the entire list.
                 */
                if (((sort_direction == ACPI_SORT_ASCENDING) &&
                     (obj_desc->integer.value < previous_value)) ||
                    ((sort_direction == ACPI_SORT_DESCENDING) &&
                     (obj_desc->integer.value > previous_value))) {
-                       status =
-                           acpi_ns_sort_list(return_object->package.elements,
-                                             outer_element_count, sort_index,
-                                             sort_direction);
-                       if (ACPI_FAILURE(status)) {
-                               return (status);
-                       }
+                       acpi_ns_sort_list(return_object->package.elements,
+                                         outer_element_count, sort_index,
+                                         sort_direction);
 
                        data->flags |= ACPI_OBJECT_REPAIRED;
 
@@ -523,89 +517,6 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data,
        return (AE_OK);
 }
 
-/******************************************************************************
- *
- * FUNCTION:    acpi_ns_remove_null_elements
- *
- * PARAMETERS:  Data                - Pointer to validation data structure
- *              package_type        - An acpi_return_package_types value
- *              obj_desc            - A Package object
- *
- * RETURN:      None.
- *
- * DESCRIPTION: Remove all NULL package elements from packages that contain
- *              a variable number of sub-packages.
- *
- *****************************************************************************/
-
-void
-acpi_ns_remove_null_elements(struct acpi_predefined_data *data,
-                            u8 package_type,
-                            union acpi_operand_object *obj_desc)
-{
-       union acpi_operand_object **source;
-       union acpi_operand_object **dest;
-       u32 count;
-       u32 new_count;
-       u32 i;
-
-       ACPI_FUNCTION_NAME(ns_remove_null_elements);
-
-       /*
-        * PTYPE1 packages contain no subpackages.
-        * PTYPE2 packages contain a variable number of sub-packages. We can
-        * safely remove all NULL elements from the PTYPE2 packages.
-        */
-       switch (package_type) {
-       case ACPI_PTYPE1_FIXED:
-       case ACPI_PTYPE1_VAR:
-       case ACPI_PTYPE1_OPTION:
-               return;
-
-       case ACPI_PTYPE2:
-       case ACPI_PTYPE2_COUNT:
-       case ACPI_PTYPE2_PKG_COUNT:
-       case ACPI_PTYPE2_FIXED:
-       case ACPI_PTYPE2_MIN:
-       case ACPI_PTYPE2_REV_FIXED:
-               break;
-
-       default:
-               return;
-       }
-
-       count = obj_desc->package.count;
-       new_count = count;
-
-       source = obj_desc->package.elements;
-       dest = source;
-
-       /* Examine all elements of the package object, remove nulls */
-
-       for (i = 0; i < count; i++) {
-               if (!*source) {
-                       new_count--;
-               } else {
-                       *dest = *source;
-                       dest++;
-               }
-               source++;
-       }
-
-       /* Update parent package if any null elements were removed */
-
-       if (new_count < count) {
-               ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
-                                 "%s: Found and removed %u NULL elements\n",
-                                 data->pathname, (count - new_count)));
-
-               /* NULL terminate list and update the package count */
-
-               *dest = NULL;
-               obj_desc->package.count = new_count;
-       }
-}
-
 /******************************************************************************
  *
  * FUNCTION:    acpi_ns_sort_list
@@ -615,15 +526,16 @@ acpi_ns_remove_null_elements(struct acpi_predefined_data *data,
  *              Index               - Sort by which package element
  *              sort_direction      - Ascending or Descending sort
  *
- * RETURN:      Status
+ * RETURN:      None
  *
  * DESCRIPTION: Sort the objects that are in a package element list.
  *
- * NOTE: Assumes that all NULL elements have been removed from the package.
+ * NOTE: Assumes that all NULL elements have been removed from the package,
+ *       and that all elements have been verified to be of type Integer.
  *
  *****************************************************************************/
 
-static acpi_status
+static void
 acpi_ns_sort_list(union acpi_operand_object **elements,
                  u32 count, u32 index, u8 sort_direction)
 {
@@ -652,6 +564,4 @@ acpi_ns_sort_list(union acpi_operand_object **elements,
                        }
                }
        }
-
-       return (AE_OK);
 }
index 7e865639a928746abb4d94039dc771d8d40245fa..08f8b3f5ccaaeb2db41eba557e152e415af29628 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 47d91e668a1bfc25436a0993b3e04b3397aed490..24d05a87a2a37c120e580537345cf331eb2eea92 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d7e6b52b4482cd2654c600932c173f77ae2b9203..00e79fb260295e6647f336e9efa6237b0cf9230e 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f0c0892bc7e5c6babc8d46955d46d1d93f24bd82..ebef8a7fd7071f3c05c0e486e65552d5f007bf70 100644 (file)
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -562,25 +562,20 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
                return (AE_BAD_PARAMETER);
        }
 
-       /* Run _STA to determine if device is present */
-
-       status = acpi_ut_execute_STA(node, &flags);
-       if (ACPI_FAILURE(status)) {
-               return (AE_CTRL_DEPTH);
-       }
-
-       if (!(flags & ACPI_STA_DEVICE_PRESENT) &&
-           !(flags & ACPI_STA_DEVICE_FUNCTIONING)) {
-               /*
-                * Don't examine the children of the device only when the
-                * device is neither present nor functional. See ACPI spec,
-                * description of _STA for more information.
-                */
-               return (AE_CTRL_DEPTH);
-       }
-
-       /* Filter based on device HID & CID */
-
+       /*
+        * First, filter based on the device HID and CID.
+        *
+        * 01/2010: For this case where a specific HID is requested, we don't
+        * want to run _STA until we have an actual HID match. Thus, we will
+        * not unnecessarily execute _STA on devices for which the caller
+        * doesn't care about. Previously, _STA was executed unconditionally
+        * on all devices found here.
+        *
+        * A side-effect of this change is that now we will continue to search
+        * for a matching HID even under device trees where the parent device
+        * would have returned a _STA that indicates it is not present or
+        * not functioning (thus aborting the search on that branch).
+        */
        if (info->hid != NULL) {
                status = acpi_ut_execute_HID(node, &hid);
                if (status == AE_NOT_FOUND) {
@@ -620,6 +615,25 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
                }
        }
 
+       /* Run _STA to determine if device is present */
+
+       status = acpi_ut_execute_STA(node, &flags);
+       if (ACPI_FAILURE(status)) {
+               return (AE_CTRL_DEPTH);
+       }
+
+       if (!(flags & ACPI_STA_DEVICE_PRESENT) &&
+           !(flags & ACPI_STA_DEVICE_FUNCTIONING)) {
+               /*
+                * Don't examine the children of the device only when the
+                * device is neither present nor functional. See ACPI spec,
+                * description of _STA for more information.
+                */
+               return (AE_CTRL_DEPTH);
+       }
+
+       /* We have a valid device, invoke the user function */
+
        status = info->user_function(obj_handle, nesting_level, info->context,
                                     return_value);
        return (status);
index e611dd961b200ba6f8afd6cebe23b282efe503f7..b01e45a415e3e44a0f40d69c87a95555ac37554a 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 0cc6ba01a49543c27eb669fdf662f8db31a587d5..eafef24ea448f9f78884c09d853bb8da1244cb41 100644 (file)
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index b161f3544b51eaa82ab98350350b155f0669cf68..00493e108a0178231748918d4784fa6338f3141d 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -403,7 +403,7 @@ acpi_ps_get_next_simple_arg(struct acpi_parse_state *parser_state,
                /* Get 1 byte from the AML stream */
 
                opcode = AML_BYTE_OP;
-               arg->common.value.integer = (acpi_integer) * aml;
+               arg->common.value.integer = (u64) *aml;
                length = 1;
                break;
 
index 0988e4a8901da1c262230c79013be926f089c733..59aabaeab1d343e5d50faef48bc82fd63c1e5711 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3bc3a60194d61cdd91ee3b60def0e67377aa6212..2b0c3be2b1b886dc07a36ddd4e05a730a57d5b1c 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 4df8f139026c697d4b16a68f315038d94553f8c4..8d81542194d457424d97afc5ed3fd1755a970cf9 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 2feca5ca95811caf12ca6957ee6f0a9fee2ca918..40e2b279ea1281d0fa1e206238d2b1379ec5d403 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 4d3389118ec3b481edab739987352d629de53e17..d4b970c3630badddb8ea5992cd374b8ffc2379b0 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index e636e078ad3deb7edd07259df902b5f4bb2618e5..fe29eee5adb1560686e72db794b1986805c1793b 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 78b8b791f2ae4c3473cbabd111a6bcb881ce7917..8abb9629443df0f6cf8f769284b5684f6c89ddcd 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d0c1b91eb8caa4731b81c71b94df969f17327127..6064dd4e94c25fdb7485ee2e782d4c601a4fe30f 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1e437bfd8db5c3a1f0e95473d18cec813b673999..226c806ae98681be6a1a47a63fd742eab9f6f42e 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3c4dcc3d1069097f4255b92d5b2eaa68119b8424..d6ebf7ec622d6e8d46d9ddb5536fa7047494d90a 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a3c23d686d5f54ccf324fedb8ab29742c81bd888..f2ee3b54860959c70c0366ac0d14bc583e6d12bd 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -182,7 +182,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
 
        /*
         * Loop through the ACPI_INTERNAL_OBJECTS - Each object should be a
-        * package that in turn contains an acpi_integer Address, a u8 Pin,
+        * package that in turn contains an u64 Address, a u8 Pin,
         * a Name, and a u8 source_index.
         */
        top_object_list = package_object->package.elements;
index 3f0ca5a12d345f870cd7c9d3adddce5c6e9f5fae..f859b0386fe462d372b45a74a4159f02106e7489 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 77b25fdb459c1e5036026854ed710f28363e21c9..1fd868b964fd2e7891ec8e358d5b37003cc68884 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 35a49aa956096c8d0d5bf8cb9e4e4c4bab9bdb72..33bff17c0bbce1900fd693267df986e6f3d653b2 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 2e0256983aa60b7edf6ee5a21ad1e5896a8e0902..545da40d7fa76cc56dea27e3963050026aaa12f5 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1b1dbc69f08719921cd58a1ff0eb20b0a57ff97f..fd057c72d25250be54580bafe82373ec644880a6 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ddc76cebdc925c7457ee4632c327caa2a325bb1c..887b8ba8c432e9e7d4771bd0343856952e415b55 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 5bc49a553284bd3abb7804e73cce1a5bb7e84727..07de352fa4434b4b6fc4e9099a93a3f8a237f142 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index bc03d59668298df64502fa3292d22a7e18b25820..22cfcfbd9fff77cd4cd5bb77be80c244461b2df5 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f27feb4772f6306b10a3a897f3f2759f5fa8c237..9f6a6e7e1c8e59a946624804ecd2354fd5a9c289 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c016335fb75974465a33da3f9b42bbf3b8f9781c..f43fbe0fc3fccf0ac8fc070f2fbf0a361b3770fe 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1054dfd49207dcc51910ae1846dd2cf16a20b290..e252180ce61c1399de74ab3fae03ca1f859516cb 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 63e82329a9e858ca81e1169daf1bf0f4f40e0e14..7ec02b0f69e0fd30051adea4a6e9c4a344a6b274 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1f15497f00d10dd4319317a0a312ac8be4d2f2f5..02723a9fb10c9f99c5fed148cfb45c939d609802 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a88f02bd6c94042e03ce24be89b2669a2182809b..5217a6159a3107b52dfb16e6524f9f632389bf4d 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 85ea834199e253b4f36dc86820ceaf51ca2ddbde..dda6e8c497d3b19c9cc0ce164f8411b09c64659a 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 7580f6b3069ec5ecaf7303be5ff88eb5087683c4..3d706b8fd449a43879a4552436c45d620691bc2e 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f857c5efb79f6d2cb2dc5d3bc9e9ae4376a51865..97ec3621e71d1f35cdb8c0b8dfe7eb46df27a9bd 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 527d729f681506d160c0e93611f60439c0dcb740..983510640059a5bf24feb6e9d85620e918223ee3 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -460,8 +460,7 @@ ACPI_EXPORT_SYMBOL(acpi_ut_status_exit)
 void
 acpi_ut_value_exit(u32 line_number,
                   const char *function_name,
-                  const char *module_name,
-                  u32 component_id, acpi_integer value)
+                  const char *module_name, u32 component_id, u64 value)
 {
 
        acpi_debug_print(ACPI_LV_FUNCTIONS,
index 96e26e70c63debb1087fe55f0bb7849e49739301..16b51c69606a342ed26879f6dccdd605ed9a3201 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 5d54e36ab4536eb151acf54cf4a11c89dd9796de..7f5e734ce7f7a1e1b05025765bb33ab29093f4ec 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -348,7 +348,7 @@ acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node,
 acpi_status
 acpi_ut_evaluate_numeric_object(char *object_name,
                                struct acpi_namespace_node *device_node,
-                               acpi_integer *value)
+                               u64 *value)
 {
        union acpi_operand_object *obj_desc;
        acpi_status status;
index 3f2c68f4e9598a58df4896c9bb0ea128fb46bbec..eda3e656c4afd50fecb281e35f55240fdebc2232 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -234,7 +234,7 @@ static const char acpi_gbl_hex_to_ascii[] = {
  *
  ******************************************************************************/
 
-char acpi_ut_hex_to_ascii_char(acpi_integer integer, u32 position)
+char acpi_ut_hex_to_ascii_char(u64 integer, u32 position)
 {
 
        return (acpi_gbl_hex_to_ascii[(integer >> position) & 0xF]);
index 52eaae40455476f02f30be6cbfff0210f026bd23..1397fadd0d4b14807b00650732fee18970e5328b 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2009, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 9d0919ebf7b00286153f354bd77a026d6a066c24..a39c93dac7193794e3a063e89a6432db9ff9cc67 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 25e03120686d8f5f899003d695f5be59102a20f6..b081cd46a15f83f5f3eaf114b2b10c52accdf496 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2009, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c9f682d640efb05edd8ba1b4b18116328ed3ab2b..35059a14eb72c87eaa86e6345a477822ece004ec 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -70,9 +70,8 @@ ACPI_MODULE_NAME("utmath")
  *
  ******************************************************************************/
 acpi_status
-acpi_ut_short_divide(acpi_integer dividend,
-                    u32 divisor,
-                    acpi_integer * out_quotient, u32 * out_remainder)
+acpi_ut_short_divide(u64 dividend,
+                    u32 divisor, u64 *out_quotient, u32 *out_remainder)
 {
        union uint64_overlay dividend_ovl;
        union uint64_overlay quotient;
@@ -126,9 +125,8 @@ acpi_ut_short_divide(acpi_integer dividend,
  ******************************************************************************/
 
 acpi_status
-acpi_ut_divide(acpi_integer in_dividend,
-              acpi_integer in_divisor,
-              acpi_integer * out_quotient, acpi_integer * out_remainder)
+acpi_ut_divide(u64 in_dividend,
+              u64 in_divisor, u64 *out_quotient, u64 *out_remainder)
 {
        union uint64_overlay dividend;
        union uint64_overlay divisor;
@@ -199,9 +197,8 @@ acpi_ut_divide(acpi_integer in_dividend,
                 * The 64-bit remainder must be generated.
                 */
                partial1 = quotient.part.lo * divisor.part.hi;
-               partial2.full =
-                   (acpi_integer) quotient.part.lo * divisor.part.lo;
-               partial3.full = (acpi_integer) partial2.part.hi + partial1;
+               partial2.full = (u64) quotient.part.lo * divisor.part.lo;
+               partial3.full = (u64) partial2.part.hi + partial1;
 
                remainder.part.hi = partial3.part.lo;
                remainder.part.lo = partial2.part.lo;
@@ -257,9 +254,8 @@ acpi_ut_divide(acpi_integer in_dividend,
  *
  ******************************************************************************/
 acpi_status
-acpi_ut_short_divide(acpi_integer in_dividend,
-                    u32 divisor,
-                    acpi_integer * out_quotient, u32 * out_remainder)
+acpi_ut_short_divide(u64 in_dividend,
+                    u32 divisor, u64 *out_quotient, u32 *out_remainder)
 {
 
        ACPI_FUNCTION_TRACE(ut_short_divide);
@@ -284,9 +280,8 @@ acpi_ut_short_divide(acpi_integer in_dividend,
 }
 
 acpi_status
-acpi_ut_divide(acpi_integer in_dividend,
-              acpi_integer in_divisor,
-              acpi_integer * out_quotient, acpi_integer * out_remainder)
+acpi_ut_divide(u64 in_dividend,
+              u64 in_divisor, u64 *out_quotient, u64 *out_remainder)
 {
        ACPI_FUNCTION_TRACE(ut_divide);
 
index 6c6a5137b72842f2c4883a732dd1ce9d5edd0b71..32982e2ac38489d191ae7fa967590d227d491c49 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -724,13 +724,12 @@ acpi_name acpi_ut_repair_name(char *name)
  *
  ******************************************************************************/
 
-acpi_status
-acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer)
+acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 * ret_integer)
 {
        u32 this_digit = 0;
-       acpi_integer return_value = 0;
-       acpi_integer quotient;
-       acpi_integer dividend;
+       u64 return_value = 0;
+       u64 quotient;
+       u64 dividend;
        u32 to_integer_op = (base == ACPI_ANY_BASE);
        u32 mode32 = (acpi_gbl_integer_byte_width == 4);
        u8 valid_digits = 0;
@@ -844,9 +843,8 @@ acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer)
 
                /* Divide the digit into the correct position */
 
-               (void)
-                   acpi_ut_short_divide((dividend - (acpi_integer) this_digit),
-                                        base, &quotient, NULL);
+               (void)acpi_ut_short_divide((dividend - (u64) this_digit),
+                                          base, &quotient, NULL);
 
                if (return_value > quotient) {
                        if (to_integer_op) {
index 80bb6515411791898cacbee2c3c71c92bcc85180..55d014ed6d5593d7a3b4550bd1f3a14edc2a4a6d 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -50,7 +50,7 @@ ACPI_MODULE_NAME("utmutex")
 /* Local prototypes */
 static acpi_status acpi_ut_create_mutex(acpi_mutex_handle mutex_id);
 
-static acpi_status acpi_ut_delete_mutex(acpi_mutex_handle mutex_id);
+static void acpi_ut_delete_mutex(acpi_mutex_handle mutex_id);
 
 /*******************************************************************************
  *
@@ -114,7 +114,7 @@ void acpi_ut_mutex_terminate(void)
        /* Delete each predefined mutex object */
 
        for (i = 0; i < ACPI_NUM_MUTEX; i++) {
-               (void)acpi_ut_delete_mutex(i);
+               acpi_ut_delete_mutex(i);
        }
 
        /* Delete the spinlocks */
@@ -146,10 +146,6 @@ static acpi_status acpi_ut_create_mutex(acpi_mutex_handle mutex_id)
 
        ACPI_FUNCTION_TRACE_U32(ut_create_mutex, mutex_id);
 
-       if (mutex_id > ACPI_MAX_MUTEX) {
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
-       }
-
        if (!acpi_gbl_mutex_info[mutex_id].mutex) {
                status =
                    acpi_os_create_mutex(&acpi_gbl_mutex_info[mutex_id].mutex);
@@ -173,21 +169,15 @@ static acpi_status acpi_ut_create_mutex(acpi_mutex_handle mutex_id)
  *
  ******************************************************************************/
 
-static acpi_status acpi_ut_delete_mutex(acpi_mutex_handle mutex_id)
+static void acpi_ut_delete_mutex(acpi_mutex_handle mutex_id)
 {
 
        ACPI_FUNCTION_TRACE_U32(ut_delete_mutex, mutex_id);
 
-       if (mutex_id > ACPI_MAX_MUTEX) {
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
-       }
-
        acpi_os_delete_mutex(acpi_gbl_mutex_info[mutex_id].mutex);
 
        acpi_gbl_mutex_info[mutex_id].mutex = NULL;
        acpi_gbl_mutex_info[mutex_id].thread_id = ACPI_MUTEX_NOT_ACQUIRED;
-
-       return_ACPI_STATUS(AE_OK);
 }
 
 /*******************************************************************************
index 42e658b543f1a33ad20b4306d9f91ca16f836e65..3356f0cb0745281d11b764ab971025535d39b486 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 91b7c00236f41f5e1d9858d6a1f4cc5ddf8e9909..7965919000b1755d078ccb876c143ca2e54c24f0 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 0440c958f5a47fc9cc001b4b459d967bbc68e07b..d35d109b8da22461b479fb3e849a4750dc25f9f1 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index b1f5f680bc783c7cca12adefd708a5de0ee97272..db9d8ca57987bc53b902274bb48a704438dbb525 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index cada73ffdfa7f9323264efe430afedb7abeb6f41..58d2c91ba62ba3a14c92bd530f8592aa7259a4ca 100644 (file)
@@ -324,8 +324,8 @@ static int extract_package(struct acpi_battery *battery,
                                strncpy(ptr, element->string.pointer, 32);
                        else if (element->type == ACPI_TYPE_INTEGER) {
                                strncpy(ptr, (u8 *)&element->integer.value,
-                                       sizeof(acpi_integer));
-                               ptr[sizeof(acpi_integer)] = 0;
+                                       sizeof(u64));
+                               ptr[sizeof(u64)] = 0;
                        } else
                                *ptr = 0; /* don't have value */
                } else {
index 27e0b92b2e39c01a1c7cb1e8e9dd305c1bf613b0..d7a6bbbb834cb6d266682183c0ccf46436ca7008 100644 (file)
@@ -597,7 +597,7 @@ static u32 acpi_ec_gpe_handler(void *data)
 
 static acpi_status
 acpi_ec_space_handler(u32 function, acpi_physical_address address,
-                     u32 bits, acpi_integer *value,
+                     u32 bits, u64 *value,
                      void *handler_context, void *region_context)
 {
        struct acpi_ec *ec = handler_context;
@@ -628,7 +628,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
                ++address;
                if (function == ACPI_READ) {
                        result = acpi_ec_read(ec, address, &temp);
-                       (*value) |= ((acpi_integer)temp) << i;
+                       (*value) |= ((u64)temp) << i;
                } else {
                        temp = 0xff & ((*value) >> i);
                        result = acpi_ec_write(ec, address, temp);
index 4c8fcff662cf260aefef315a716256c913427a3a..6d5b64b7d526e8c00f3e695d999708f55aae3540 100644 (file)
@@ -87,7 +87,7 @@ static int acpi_find_bridge_device(struct device *dev, acpi_handle * handle)
 /* Get device's handler per its address under its parent */
 struct acpi_find_child {
        acpi_handle handle;
-       acpi_integer address;
+       u64 address;
 };
 
 static acpi_status
@@ -106,7 +106,7 @@ do_acpi_find_child(acpi_handle handle, u32 lvl, void *context, void **rv)
        return AE_OK;
 }
 
-acpi_handle acpi_get_child(acpi_handle parent, acpi_integer address)
+acpi_handle acpi_get_child(acpi_handle parent, u64 address)
 {
        struct acpi_find_child find = { NULL, address };
 
index 02e8464e480f9e7dea0d3a25ba935ea55e27b8e1..8e6d8665f0aecd54a6895046c13071b831a250c6 100644 (file)
@@ -436,7 +436,7 @@ acpi_status acpi_os_remove_interrupt_handler(u32 irq, acpi_osd_handler handler)
  * Running in interpreter thread context, safe to sleep
  */
 
-void acpi_os_sleep(acpi_integer ms)
+void acpi_os_sleep(u64 ms)
 {
        schedule_timeout_interruptible(msecs_to_jiffies(ms));
 }
@@ -603,7 +603,7 @@ acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
 
 acpi_status
 acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
-                               acpi_integer value, u32 width)
+                               u64 value, u32 width)
 {
        int result, size;
 
index dc4ffadf81220a2541f68f773514d430491b75b7..834c5af0de4bead0ec1b77f67d6d0357a8ccb1e6 100644 (file)
@@ -71,17 +71,17 @@ static const struct acpi_device_id power_meter_ids[] = {
 MODULE_DEVICE_TABLE(acpi, power_meter_ids);
 
 struct acpi_power_meter_capabilities {
-       acpi_integer            flags;
-       acpi_integer            units;
-       acpi_integer            type;
-       acpi_integer            accuracy;
-       acpi_integer            sampling_time;
-       acpi_integer            min_avg_interval;
-       acpi_integer            max_avg_interval;
-       acpi_integer            hysteresis;
-       acpi_integer            configurable_cap;
-       acpi_integer            min_cap;
-       acpi_integer            max_cap;
+       u64             flags;
+       u64             units;
+       u64             type;
+       u64             accuracy;
+       u64             sampling_time;
+       u64             min_avg_interval;
+       u64             max_avg_interval;
+       u64             hysteresis;
+       u64             configurable_cap;
+       u64             min_cap;
+       u64             max_cap;
 };
 
 struct acpi_power_meter_resource {
@@ -93,9 +93,9 @@ struct acpi_power_meter_resource {
        acpi_string             model_number;
        acpi_string             serial_number;
        acpi_string             oem_info;
-       acpi_integer            power;
-       acpi_integer            cap;
-       acpi_integer            avg_interval;
+       u64             power;
+       u64             cap;
+       u64             avg_interval;
        int                     sensors_valid;
        unsigned long           sensors_last_updated;
        struct sensor_device_attribute  sensors[NUM_SENSORS];
@@ -402,7 +402,7 @@ static ssize_t show_val(struct device *dev,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct acpi_device *acpi_dev = to_acpi_device(dev);
        struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
-       acpi_integer val = 0;
+       u64 val = 0;
 
        switch (attr->index) {
        case 0:
index cc978a8c00b797d6c5e9d4300a857a7fa612d6ea..37dfce749398b35abc6ef3b00fac13ce678146b3 100644 (file)
@@ -360,7 +360,7 @@ static int acpi_processor_get_power_info_default(struct acpi_processor *pr)
 static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
 {
        acpi_status status = 0;
-       acpi_integer count;
+       u64 count;
        int current_count;
        int i;
        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
index 1c5d7a8b2fdfc86f2b51e434625fdc497aa099e5..7ded7542fc9ddfa0a20a762a7d78214e05131720 100644 (file)
@@ -660,7 +660,7 @@ static int acpi_processor_get_throttling_fadt(struct acpi_processor *pr)
 
 #ifdef CONFIG_X86
 static int acpi_throttling_rdmsr(struct acpi_processor *pr,
-                                       acpi_integer * value)
+                                       u64 *value)
 {
        struct cpuinfo_x86 *c;
        u64 msr_high, msr_low;
@@ -681,13 +681,13 @@ static int acpi_throttling_rdmsr(struct acpi_processor *pr,
                rdmsr_safe(MSR_IA32_THERM_CONTROL,
                        (u32 *)&msr_low , (u32 *) &msr_high);
                msr = (msr_high << 32) | msr_low;
-               *value = (acpi_integer) msr;
+               *value = (u64) msr;
                ret = 0;
        }
        return ret;
 }
 
-static int acpi_throttling_wrmsr(struct acpi_processor *pr, acpi_integer value)
+static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value)
 {
        struct cpuinfo_x86 *c;
        unsigned int cpu;
@@ -711,14 +711,14 @@ static int acpi_throttling_wrmsr(struct acpi_processor *pr, acpi_integer value)
 }
 #else
 static int acpi_throttling_rdmsr(struct acpi_processor *pr,
-                               acpi_integer * value)
+                               u64 *value)
 {
        printk(KERN_ERR PREFIX
                "HARDWARE addr space,NOT supported yet\n");
        return -1;
 }
 
-static int acpi_throttling_wrmsr(struct acpi_processor *pr, acpi_integer value)
+static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value)
 {
        printk(KERN_ERR PREFIX
                "HARDWARE addr space,NOT supported yet\n");
@@ -727,7 +727,7 @@ static int acpi_throttling_wrmsr(struct acpi_processor *pr, acpi_integer value)
 #endif
 
 static int acpi_read_throttling_status(struct acpi_processor *pr,
-                                       acpi_integer *value)
+                                       u64 *value)
 {
        u32 bit_width, bit_offset;
        u64 ptc_value;
@@ -746,7 +746,7 @@ static int acpi_read_throttling_status(struct acpi_processor *pr,
                                  address, (u32 *) &ptc_value,
                                  (u32) (bit_width + bit_offset));
                ptc_mask = (1 << bit_width) - 1;
-               *value = (acpi_integer) ((ptc_value >> bit_offset) & ptc_mask);
+               *value = (u64) ((ptc_value >> bit_offset) & ptc_mask);
                ret = 0;
                break;
        case ACPI_ADR_SPACE_FIXED_HARDWARE:
@@ -760,7 +760,7 @@ static int acpi_read_throttling_status(struct acpi_processor *pr,
 }
 
 static int acpi_write_throttling_state(struct acpi_processor *pr,
-                               acpi_integer value)
+                               u64 value)
 {
        u32 bit_width, bit_offset;
        u64 ptc_value;
@@ -793,7 +793,7 @@ static int acpi_write_throttling_state(struct acpi_processor *pr,
 }
 
 static int acpi_get_throttling_state(struct acpi_processor *pr,
-                               acpi_integer value)
+                               u64 value)
 {
        int i;
 
@@ -808,7 +808,7 @@ static int acpi_get_throttling_state(struct acpi_processor *pr,
 }
 
 static int acpi_get_throttling_value(struct acpi_processor *pr,
-                       int state, acpi_integer *value)
+                       int state, u64 *value)
 {
        int ret = -1;
 
@@ -826,7 +826,7 @@ static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr)
 {
        int state = 0;
        int ret;
-       acpi_integer value;
+       u64 value;
 
        if (!pr)
                return -EINVAL;
@@ -993,7 +993,7 @@ static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr,
                                             int state, bool force)
 {
        int ret;
-       acpi_integer value;
+       u64 value;
 
        if (!pr)
                return -EINVAL;
index 811fec10462b7f41b89bcc0735b3b99c1819a6b3..11882dbe20944e8b522296d0431ca33a1ba2a57c 100644 (file)
@@ -107,12 +107,12 @@ acpi_extract_package(union acpi_object *package,
                case ACPI_TYPE_INTEGER:
                        switch (format_string[i]) {
                        case 'N':
-                               size_required += sizeof(acpi_integer);
-                               tail_offset += sizeof(acpi_integer);
+                               size_required += sizeof(u64);
+                               tail_offset += sizeof(u64);
                                break;
                        case 'S':
                                size_required +=
-                                   sizeof(char *) + sizeof(acpi_integer) +
+                                   sizeof(char *) + sizeof(u64) +
                                    sizeof(char);
                                tail_offset += sizeof(char *);
                                break;
@@ -193,17 +193,17 @@ acpi_extract_package(union acpi_object *package,
                case ACPI_TYPE_INTEGER:
                        switch (format_string[i]) {
                        case 'N':
-                               *((acpi_integer *) head) =
+                               *((u64 *) head) =
                                    element->integer.value;
-                               head += sizeof(acpi_integer);
+                               head += sizeof(u64);
                                break;
                        case 'S':
                                pointer = (u8 **) head;
                                *pointer = tail;
-                               *((acpi_integer *) tail) =
+                               *((u64 *) tail) =
                                    element->integer.value;
-                               head += sizeof(acpi_integer *);
-                               tail += sizeof(acpi_integer);
+                               head += sizeof(u64 *);
+                               tail += sizeof(u64);
                                /* NULL terminate string */
                                *tail = (char)0;
                                tail += sizeof(char);
index b765790b32be1841d652d3e834c6013950700efc..6e9b49149fce4b675deb81b974d60f281439aff7 100644 (file)
@@ -759,7 +759,7 @@ acpi_video_bus_POST_options(struct acpi_video_bus *video,
 static int
 acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag)
 {
-       acpi_integer status = 0;
+       u64 status = 0;
        union acpi_object arg0 = { ACPI_TYPE_INTEGER };
        struct acpi_object_list args = { 1, &arg0 };
 
index 56c6374a39895702a7de1994e01422dee89d720f..01c52c415bdc647ab35ed21706f99726469cfc15 100644 (file)
@@ -446,9 +446,9 @@ config PATA_JMICRON
 
 config PATA_LEGACY
        tristate "Legacy ISA PATA support (Experimental)"
-       depends on ISA && EXPERIMENTAL
+       depends on (ISA || PCI)  && EXPERIMENTAL
        help
-         This option enables support for ISA/VLB bus legacy PATA
+         This option enables support for ISA/VLB/PCI bus legacy PATA
          ports and allows them to be accessed via the new ATA layer.
 
          If unsure, say N.
index a6a736a7dbf2ea1bbe09dd5afae1dd37d44ded55..6bd930b93bccf8f19eb80967429d6a980908dd29 100644 (file)
@@ -93,6 +93,9 @@ enum {
        AHCI_CMD_TBL_AR_SZ      = AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS,
        AHCI_PORT_PRIV_DMA_SZ   = AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ +
                                  AHCI_RX_FIS_SZ,
+       AHCI_PORT_PRIV_FBS_DMA_SZ       = AHCI_CMD_SLOT_SZ +
+                                         AHCI_CMD_TBL_AR_SZ +
+                                         (AHCI_RX_FIS_SZ * 16),
        AHCI_IRQ_ON_SG          = (1 << 31),
        AHCI_CMD_ATAPI          = (1 << 5),
        AHCI_CMD_WRITE          = (1 << 6),
@@ -170,6 +173,7 @@ enum {
        PORT_SCR_ERR            = 0x30, /* SATA phy register: SError */
        PORT_SCR_ACT            = 0x34, /* SATA phy register: SActive */
        PORT_SCR_NTF            = 0x3c, /* SATA phy register: SNotification */
+       PORT_FBS                = 0x40, /* FIS-based Switching */
 
        /* PORT_IRQ_{STAT,MASK} bits */
        PORT_IRQ_COLD_PRES      = (1 << 31), /* cold presence detect */
@@ -208,6 +212,7 @@ enum {
        PORT_CMD_ASP            = (1 << 27), /* Aggressive Slumber/Partial */
        PORT_CMD_ALPE           = (1 << 26), /* Aggressive Link PM enable */
        PORT_CMD_ATAPI          = (1 << 24), /* Device is ATAPI */
+       PORT_CMD_FBSCP          = (1 << 22), /* FBS Capable Port */
        PORT_CMD_PMP            = (1 << 17), /* PMP attached */
        PORT_CMD_LIST_ON        = (1 << 15), /* cmd list DMA engine running */
        PORT_CMD_FIS_ON         = (1 << 14), /* FIS DMA engine running */
@@ -222,6 +227,14 @@ enum {
        PORT_CMD_ICC_PARTIAL    = (0x2 << 28), /* Put i/f in partial state */
        PORT_CMD_ICC_SLUMBER    = (0x6 << 28), /* Put i/f in slumber state */
 
+       PORT_FBS_DWE_OFFSET     = 16, /* FBS device with error offset */
+       PORT_FBS_ADO_OFFSET     = 12, /* FBS active dev optimization offset */
+       PORT_FBS_DEV_OFFSET     = 8,  /* FBS device to issue offset */
+       PORT_FBS_DEV_MASK       = (0xf << PORT_FBS_DEV_OFFSET),  /* FBS.DEV */
+       PORT_FBS_SDE            = (1 << 2), /* FBS single device error */
+       PORT_FBS_DEC            = (1 << 1), /* FBS device error clear */
+       PORT_FBS_EN             = (1 << 0), /* Enable FBS */
+
        /* hpriv->flags bits */
        AHCI_HFLAG_NO_NCQ               = (1 << 0),
        AHCI_HFLAG_IGN_IRQ_IF_ERR       = (1 << 1), /* ignore IRQ_IF_ERR */
@@ -304,6 +317,9 @@ struct ahci_port_priv {
        unsigned int            ncq_saw_dmas:1;
        unsigned int            ncq_saw_sdb:1;
        u32                     intr_mask;      /* interrupts to enable */
+       bool                    fbs_supported;  /* set iff FBS is supported */
+       bool                    fbs_enabled;    /* set iff FBS is enabled */
+       int                     fbs_last_dev;   /* save FBS.DEV of last FIS */
        /* enclosure management info per PM slot */
        struct ahci_em_priv     em_priv[EM_MAX_SLOTS];
 };
@@ -315,9 +331,12 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
 static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc);
 static int ahci_port_start(struct ata_port *ap);
 static void ahci_port_stop(struct ata_port *ap);
+static int ahci_pmp_qc_defer(struct ata_queued_cmd *qc);
 static void ahci_qc_prep(struct ata_queued_cmd *qc);
 static void ahci_freeze(struct ata_port *ap);
 static void ahci_thaw(struct ata_port *ap);
+static void ahci_enable_fbs(struct ata_port *ap);
+static void ahci_disable_fbs(struct ata_port *ap);
 static void ahci_pmp_attach(struct ata_port *ap);
 static void ahci_pmp_detach(struct ata_port *ap);
 static int ahci_softreset(struct ata_link *link, unsigned int *class,
@@ -356,10 +375,10 @@ static ssize_t ahci_show_host_version(struct device *dev,
 static ssize_t ahci_show_port_cmd(struct device *dev,
                                  struct device_attribute *attr, char *buf);
 
-DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL);
-DEVICE_ATTR(ahci_host_cap2, S_IRUGO, ahci_show_host_cap2, NULL);
-DEVICE_ATTR(ahci_host_version, S_IRUGO, ahci_show_host_version, NULL);
-DEVICE_ATTR(ahci_port_cmd, S_IRUGO, ahci_show_port_cmd, NULL);
+static DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL);
+static DEVICE_ATTR(ahci_host_cap2, S_IRUGO, ahci_show_host_cap2, NULL);
+static DEVICE_ATTR(ahci_host_version, S_IRUGO, ahci_show_host_version, NULL);
+static DEVICE_ATTR(ahci_port_cmd, S_IRUGO, ahci_show_port_cmd, NULL);
 
 static struct device_attribute *ahci_shost_attrs[] = {
        &dev_attr_link_power_management_policy,
@@ -390,7 +409,7 @@ static struct scsi_host_template ahci_sht = {
 static struct ata_port_operations ahci_ops = {
        .inherits               = &sata_pmp_port_ops,
 
-       .qc_defer               = sata_pmp_qc_defer_cmd_switch,
+       .qc_defer               = ahci_pmp_qc_defer,
        .qc_prep                = ahci_qc_prep,
        .qc_issue               = ahci_qc_issue,
        .qc_fill_rtf            = ahci_qc_fill_rtf,
@@ -570,6 +589,12 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
        { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */
        { PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */
+       { PCI_VDEVICE(INTEL, 0x1c02), board_ahci }, /* CPT AHCI */
+       { PCI_VDEVICE(INTEL, 0x1c03), board_ahci }, /* CPT AHCI */
+       { PCI_VDEVICE(INTEL, 0x1c04), board_ahci }, /* CPT RAID */
+       { PCI_VDEVICE(INTEL, 0x1c05), board_ahci }, /* CPT RAID */
+       { PCI_VDEVICE(INTEL, 0x1c06), board_ahci }, /* CPT RAID */
+       { PCI_VDEVICE(INTEL, 0x1c07), board_ahci }, /* CPT RAID */
 
        /* JMicron 360/1/3/5/6, match class to avoid IDE function */
        { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -2045,6 +2070,17 @@ static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
        return si;
 }
 
+static int ahci_pmp_qc_defer(struct ata_queued_cmd *qc)
+{
+       struct ata_port *ap = qc->ap;
+       struct ahci_port_priv *pp = ap->private_data;
+
+       if (!sata_pmp_attached(ap) || pp->fbs_enabled)
+               return ata_std_qc_defer(qc);
+       else
+               return sata_pmp_qc_defer_cmd_switch(qc);
+}
+
 static void ahci_qc_prep(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
@@ -2083,6 +2119,31 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
        ahci_fill_cmd_slot(pp, qc->tag, opts);
 }
 
+static void ahci_fbs_dec_intr(struct ata_port *ap)
+{
+       struct ahci_port_priv *pp = ap->private_data;
+       void __iomem *port_mmio = ahci_port_base(ap);
+       u32 fbs = readl(port_mmio + PORT_FBS);
+       int retries = 3;
+
+       DPRINTK("ENTER\n");
+       BUG_ON(!pp->fbs_enabled);
+
+       /* time to wait for DEC is not specified by AHCI spec,
+        * add a retry loop for safety.
+        */
+       writel(fbs | PORT_FBS_DEC, port_mmio + PORT_FBS);
+       fbs = readl(port_mmio + PORT_FBS);
+       while ((fbs & PORT_FBS_DEC) && retries--) {
+               udelay(1);
+               fbs = readl(port_mmio + PORT_FBS);
+       }
+
+       if (fbs & PORT_FBS_DEC)
+               dev_printk(KERN_ERR, ap->host->dev,
+                          "failed to clear device error\n");
+}
+
 static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
 {
        struct ahci_host_priv *hpriv = ap->host->private_data;
@@ -2091,12 +2152,26 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
        struct ata_link *link = NULL;
        struct ata_queued_cmd *active_qc;
        struct ata_eh_info *active_ehi;
+       bool fbs_need_dec = false;
        u32 serror;
 
-       /* determine active link */
-       ata_for_each_link(link, ap, EDGE)
-               if (ata_link_active(link))
-                       break;
+       /* determine active link with error */
+       if (pp->fbs_enabled) {
+               void __iomem *port_mmio = ahci_port_base(ap);
+               u32 fbs = readl(port_mmio + PORT_FBS);
+               int pmp = fbs >> PORT_FBS_DWE_OFFSET;
+
+               if ((fbs & PORT_FBS_SDE) && (pmp < ap->nr_pmp_links) &&
+                   ata_link_online(&ap->pmp_link[pmp])) {
+                       link = &ap->pmp_link[pmp];
+                       fbs_need_dec = true;
+               }
+
+       } else
+               ata_for_each_link(link, ap, EDGE)
+                       if (ata_link_active(link))
+                               break;
+
        if (!link)
                link = &ap->link;
 
@@ -2153,8 +2228,13 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
        }
 
        if (irq_stat & PORT_IRQ_IF_ERR) {
-               host_ehi->err_mask |= AC_ERR_ATA_BUS;
-               host_ehi->action |= ATA_EH_RESET;
+               if (fbs_need_dec)
+                       active_ehi->err_mask |= AC_ERR_DEV;
+               else {
+                       host_ehi->err_mask |= AC_ERR_ATA_BUS;
+                       host_ehi->action |= ATA_EH_RESET;
+               }
+
                ata_ehi_push_desc(host_ehi, "interface fatal error");
        }
 
@@ -2169,7 +2249,10 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
 
        if (irq_stat & PORT_IRQ_FREEZE)
                ata_port_freeze(ap);
-       else
+       else if (fbs_need_dec) {
+               ata_link_abort(link);
+               ahci_fbs_dec_intr(ap);
+       } else
                ata_port_abort(ap);
 }
 
@@ -2222,12 +2305,19 @@ static void ahci_port_intr(struct ata_port *ap)
                        /* If the 'N' bit in word 0 of the FIS is set,
                         * we just received asynchronous notification.
                         * Tell libata about it.
+                        *
+                        * Lack of SNotification should not appear in
+                        * ahci 1.2, so the workaround is unnecessary
+                        * when FBS is enabled.
                         */
-                       const __le32 *f = pp->rx_fis + RX_FIS_SDB;
-                       u32 f0 = le32_to_cpu(f[0]);
-
-                       if (f0 & (1 << 15))
-                               sata_async_notification(ap);
+                       if (pp->fbs_enabled)
+                               WARN_ON_ONCE(1);
+                       else {
+                               const __le32 *f = pp->rx_fis + RX_FIS_SDB;
+                               u32 f0 = le32_to_cpu(f[0]);
+                               if (f0 & (1 << 15))
+                                       sata_async_notification(ap);
+                       }
                }
        }
 
@@ -2321,6 +2411,15 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
 
        if (qc->tf.protocol == ATA_PROT_NCQ)
                writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
+
+       if (pp->fbs_enabled && pp->fbs_last_dev != qc->dev->link->pmp) {
+               u32 fbs = readl(port_mmio + PORT_FBS);
+               fbs &= ~(PORT_FBS_DEV_MASK | PORT_FBS_DEC);
+               fbs |= qc->dev->link->pmp << PORT_FBS_DEV_OFFSET;
+               writel(fbs, port_mmio + PORT_FBS);
+               pp->fbs_last_dev = qc->dev->link->pmp;
+       }
+
        writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
 
        ahci_sw_activity(qc->dev->link);
@@ -2333,6 +2432,9 @@ static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
        struct ahci_port_priv *pp = qc->ap->private_data;
        u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
 
+       if (pp->fbs_enabled)
+               d2h_fis += qc->dev->link->pmp * AHCI_RX_FIS_SZ;
+
        ata_tf_from_fis(d2h_fis, &qc->result_tf);
        return true;
 }
@@ -2381,6 +2483,71 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
                ahci_kick_engine(ap);
 }
 
+static void ahci_enable_fbs(struct ata_port *ap)
+{
+       struct ahci_port_priv *pp = ap->private_data;
+       void __iomem *port_mmio = ahci_port_base(ap);
+       u32 fbs;
+       int rc;
+
+       if (!pp->fbs_supported)
+               return;
+
+       fbs = readl(port_mmio + PORT_FBS);
+       if (fbs & PORT_FBS_EN) {
+               pp->fbs_enabled = true;
+               pp->fbs_last_dev = -1; /* initialization */
+               return;
+       }
+
+       rc = ahci_stop_engine(ap);
+       if (rc)
+               return;
+
+       writel(fbs | PORT_FBS_EN, port_mmio + PORT_FBS);
+       fbs = readl(port_mmio + PORT_FBS);
+       if (fbs & PORT_FBS_EN) {
+               dev_printk(KERN_INFO, ap->host->dev, "FBS is enabled.\n");
+               pp->fbs_enabled = true;
+               pp->fbs_last_dev = -1; /* initialization */
+       } else
+               dev_printk(KERN_ERR, ap->host->dev, "Failed to enable FBS\n");
+
+       ahci_start_engine(ap);
+}
+
+static void ahci_disable_fbs(struct ata_port *ap)
+{
+       struct ahci_port_priv *pp = ap->private_data;
+       void __iomem *port_mmio = ahci_port_base(ap);
+       u32 fbs;
+       int rc;
+
+       if (!pp->fbs_supported)
+               return;
+
+       fbs = readl(port_mmio + PORT_FBS);
+       if ((fbs & PORT_FBS_EN) == 0) {
+               pp->fbs_enabled = false;
+               return;
+       }
+
+       rc = ahci_stop_engine(ap);
+       if (rc)
+               return;
+
+       writel(fbs & ~PORT_FBS_EN, port_mmio + PORT_FBS);
+       fbs = readl(port_mmio + PORT_FBS);
+       if (fbs & PORT_FBS_EN)
+               dev_printk(KERN_ERR, ap->host->dev, "Failed to disable FBS\n");
+       else {
+               dev_printk(KERN_INFO, ap->host->dev, "FBS is disabled.\n");
+               pp->fbs_enabled = false;
+       }
+
+       ahci_start_engine(ap);
+}
+
 static void ahci_pmp_attach(struct ata_port *ap)
 {
        void __iomem *port_mmio = ahci_port_base(ap);
@@ -2391,6 +2558,8 @@ static void ahci_pmp_attach(struct ata_port *ap)
        cmd |= PORT_CMD_PMP;
        writel(cmd, port_mmio + PORT_CMD);
 
+       ahci_enable_fbs(ap);
+
        pp->intr_mask |= PORT_IRQ_BAD_PMP;
        writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
 }
@@ -2401,6 +2570,8 @@ static void ahci_pmp_detach(struct ata_port *ap)
        struct ahci_port_priv *pp = ap->private_data;
        u32 cmd;
 
+       ahci_disable_fbs(ap);
+
        cmd = readl(port_mmio + PORT_CMD);
        cmd &= ~PORT_CMD_PMP;
        writel(cmd, port_mmio + PORT_CMD);
@@ -2492,20 +2663,40 @@ static int ahci_pci_device_resume(struct pci_dev *pdev)
 
 static int ahci_port_start(struct ata_port *ap)
 {
+       struct ahci_host_priv *hpriv = ap->host->private_data;
        struct device *dev = ap->host->dev;
        struct ahci_port_priv *pp;
        void *mem;
        dma_addr_t mem_dma;
+       size_t dma_sz, rx_fis_sz;
 
        pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
        if (!pp)
                return -ENOMEM;
 
-       mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma,
-                                 GFP_KERNEL);
+       /* check FBS capability */
+       if ((hpriv->cap & HOST_CAP_FBS) && sata_pmp_supported(ap)) {
+               void __iomem *port_mmio = ahci_port_base(ap);
+               u32 cmd = readl(port_mmio + PORT_CMD);
+               if (cmd & PORT_CMD_FBSCP)
+                       pp->fbs_supported = true;
+               else
+                       dev_printk(KERN_WARNING, dev,
+                                  "The port is not capable of FBS\n");
+       }
+
+       if (pp->fbs_supported) {
+               dma_sz = AHCI_PORT_PRIV_FBS_DMA_SZ;
+               rx_fis_sz = AHCI_RX_FIS_SZ * 16;
+       } else {
+               dma_sz = AHCI_PORT_PRIV_DMA_SZ;
+               rx_fis_sz = AHCI_RX_FIS_SZ;
+       }
+
+       mem = dmam_alloc_coherent(dev, dma_sz, &mem_dma, GFP_KERNEL);
        if (!mem)
                return -ENOMEM;
-       memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
+       memset(mem, 0, dma_sz);
 
        /*
         * First item in chunk of DMA memory: 32-slot command table,
@@ -2523,8 +2714,8 @@ static int ahci_port_start(struct ata_port *ap)
        pp->rx_fis = mem;
        pp->rx_fis_dma = mem_dma;
 
-       mem += AHCI_RX_FIS_SZ;
-       mem_dma += AHCI_RX_FIS_SZ;
+       mem += rx_fis_sz;
+       mem_dma += rx_fis_sz;
 
        /*
         * Third item: data area for storing a single command
index 12e26c3c68e3f1d97d426bef8cd5372baf277c09..33fb614f9784a71df64df398defe93fd8d9962bd 100644 (file)
@@ -155,7 +155,7 @@ static int ata_generic_init_one(struct pci_dev *dev, const struct pci_device_id
                        return rc;
                pcim_pin_device(dev);
        }
-       return ata_pci_sff_init_one(dev, ppi, &generic_sht, NULL);
+       return ata_pci_sff_init_one(dev, ppi, &generic_sht, NULL, 0);
 }
 
 static struct pci_device_id ata_generic[] = {
index 6f3f2257d0f028ba9216b790f00f4dcf9da7ffd4..c33806654e46d5bfb984866c7bdad185c4f90ffe 100644 (file)
@@ -173,6 +173,7 @@ static int piix_sidpr_scr_read(struct ata_link *link,
                               unsigned int reg, u32 *val);
 static int piix_sidpr_scr_write(struct ata_link *link,
                                unsigned int reg, u32 val);
+static bool piix_irq_check(struct ata_port *ap);
 #ifdef CONFIG_PM
 static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
 static int piix_pci_device_resume(struct pci_dev *pdev);
@@ -291,6 +292,14 @@ static const struct pci_device_id piix_pci_tbl[] = {
        { 0x8086, 0x3b2d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
        /* SATA Controller IDE (PCH) */
        { 0x8086, 0x3b2e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
+       /* SATA Controller IDE (CPT) */
+       { 0x8086, 0x1c00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
+       /* SATA Controller IDE (CPT) */
+       { 0x8086, 0x1c01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
+       /* SATA Controller IDE (CPT) */
+       { 0x8086, 0x1c08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+       /* SATA Controller IDE (CPT) */
+       { 0x8086, 0x1c09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
        { }     /* terminate list */
 };
 
@@ -309,8 +318,13 @@ static struct scsi_host_template piix_sht = {
        ATA_BMDMA_SHT(DRV_NAME),
 };
 
-static struct ata_port_operations piix_pata_ops = {
+static struct ata_port_operations piix_sata_ops = {
        .inherits               = &ata_bmdma32_port_ops,
+       .sff_irq_check          = piix_irq_check,
+};
+
+static struct ata_port_operations piix_pata_ops = {
+       .inherits               = &piix_sata_ops,
        .cable_detect           = ata_cable_40wire,
        .set_piomode            = piix_set_piomode,
        .set_dmamode            = piix_set_dmamode,
@@ -328,10 +342,6 @@ static struct ata_port_operations ich_pata_ops = {
        .set_dmamode            = ich_set_dmamode,
 };
 
-static struct ata_port_operations piix_sata_ops = {
-       .inherits               = &ata_bmdma32_port_ops,
-};
-
 static struct ata_port_operations piix_sidpr_sata_ops = {
        .inherits               = &piix_sata_ops,
        .hardreset              = sata_std_hardreset,
@@ -962,6 +972,14 @@ static int piix_sidpr_scr_write(struct ata_link *link,
        return 0;
 }
 
+static bool piix_irq_check(struct ata_port *ap)
+{
+       if (unlikely(!ap->ioaddr.bmdma_addr))
+               return false;
+
+       return ap->ops->bmdma_status(ap) & ATA_DMA_INTR;
+}
+
 #ifdef CONFIG_PM
 static int piix_broken_suspend(void)
 {
index 1245838ac13dbe8feec67c1e4c14076e6930c23d..292fdbc0431a20e872509809ccd733683f61bb9c 100644 (file)
@@ -64,7 +64,7 @@ void ata_acpi_associate_sata_port(struct ata_port *ap)
        WARN_ON(!(ap->flags & ATA_FLAG_ACPI_SATA));
 
        if (!sata_pmp_attached(ap)) {
-               acpi_integer adr = SATA_ADR(ap->port_no, NO_PORT_MULT);
+               u64 adr = SATA_ADR(ap->port_no, NO_PORT_MULT);
 
                ap->link.device->acpi_handle =
                        acpi_get_child(ap->host->acpi_handle, adr);
@@ -74,7 +74,7 @@ void ata_acpi_associate_sata_port(struct ata_port *ap)
                ap->link.device->acpi_handle = NULL;
 
                ata_for_each_link(link, ap, EDGE) {
-                       acpi_integer adr = SATA_ADR(ap->port_no, link->pmp);
+                       u64 adr = SATA_ADR(ap->port_no, link->pmp);
 
                        link->device->acpi_handle =
                                acpi_get_child(ap->host->acpi_handle, adr);
index 6728328f3bea21309552110eca5bb5eb7f52a097..9c77b0d1a9d0fe2e50e7c7a9409e241cc35aa499 100644 (file)
@@ -3211,6 +3211,7 @@ const struct ata_timing *ata_timing_find_mode(u8 xfer_mode)
 int ata_timing_compute(struct ata_device *adev, unsigned short speed,
                       struct ata_timing *t, int T, int UT)
 {
+       const u16 *id = adev->id;
        const struct ata_timing *s;
        struct ata_timing p;
 
@@ -3228,14 +3229,18 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed,
         * PIO/MW_DMA cycle timing.
         */
 
-       if (adev->id[ATA_ID_FIELD_VALID] & 2) { /* EIDE drive */
+       if (id[ATA_ID_FIELD_VALID] & 2) {       /* EIDE drive */
                memset(&p, 0, sizeof(p));
+
                if (speed >= XFER_PIO_0 && speed <= XFER_SW_DMA_0) {
-                       if (speed <= XFER_PIO_2) p.cycle = p.cyc8b = adev->id[ATA_ID_EIDE_PIO];
-                                           else p.cycle = p.cyc8b = adev->id[ATA_ID_EIDE_PIO_IORDY];
-               } else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2) {
-                       p.cycle = adev->id[ATA_ID_EIDE_DMA_MIN];
-               }
+                       if (speed <= XFER_PIO_2)
+                               p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO];
+                       else if ((speed <= XFER_PIO_4) ||
+                                (speed == XFER_PIO_5 && !ata_id_is_cfa(id)))
+                               p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO_IORDY];
+               } else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)
+                       p.cycle = id[ATA_ID_EIDE_DMA_MIN];
+
                ata_timing_merge(&p, t, t, ATA_TIMING_CYCLE | ATA_TIMING_CYC8B);
        }
 
index d096fbcbc771a61a0537e28842d04f1149dcc7a7..bea003a24d277268fb7cd9337e9851269e0c809c 100644 (file)
@@ -1097,7 +1097,7 @@ static int ata_scsi_dev_config(struct scsi_device *sdev,
                dev->flags |= ATA_DFLAG_NO_UNLOAD;
 
        /* configure max sectors */
-       blk_queue_max_sectors(sdev->request_queue, dev->max_sectors);
+       blk_queue_max_hw_sectors(sdev->request_queue, dev->max_sectors);
 
        if (dev->class == ATA_DEV_ATAPI) {
                struct request_queue *q = sdev->request_queue;
index 730ef3c384ca190818857c89ab044006dccfe75d..02441fd57e9ef631afa04708423044569c463716 100644 (file)
@@ -1763,24 +1763,50 @@ irqreturn_t ata_sff_interrupt(int irq, void *dev_instance)
 {
        struct ata_host *host = dev_instance;
        unsigned int i;
-       unsigned int handled = 0;
+       unsigned int handled = 0, polling = 0;
        unsigned long flags;
 
        /* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */
        spin_lock_irqsave(&host->lock, flags);
 
        for (i = 0; i < host->n_ports; i++) {
-               struct ata_port *ap;
+               struct ata_port *ap = host->ports[i];
+               struct ata_queued_cmd *qc;
 
-               ap = host->ports[i];
-               if (ap &&
-                   !(ap->flags & ATA_FLAG_DISABLED)) {
-                       struct ata_queued_cmd *qc;
+               if (unlikely(ap->flags & ATA_FLAG_DISABLED))
+                       continue;
 
-                       qc = ata_qc_from_tag(ap, ap->link.active_tag);
-                       if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
-                           (qc->flags & ATA_QCFLAG_ACTIVE))
+               qc = ata_qc_from_tag(ap, ap->link.active_tag);
+               if (qc) {
+                       if (!(qc->tf.flags & ATA_TFLAG_POLLING))
                                handled |= ata_sff_host_intr(ap, qc);
+                       else
+                               polling |= 1 << i;
+               }
+       }
+
+       /*
+        * If no port was expecting IRQ but the controller is actually
+        * asserting IRQ line, nobody cared will ensue.  Check IRQ
+        * pending status if available and clear spurious IRQ.
+        */
+       if (!handled) {
+               for (i = 0; i < host->n_ports; i++) {
+                       struct ata_port *ap = host->ports[i];
+
+                       if (polling & (1 << i))
+                               continue;
+
+                       if (!ap->ops->sff_irq_check ||
+                           !ap->ops->sff_irq_check(ap))
+                               continue;
+
+                       if (printk_ratelimit())
+                               ata_port_printk(ap, KERN_INFO,
+                                               "clearing spurious IRQ\n");
+
+                       ap->ops->sff_check_status(ap);
+                       ap->ops->sff_irq_clear(ap);
                }
        }
 
@@ -3011,6 +3037,7 @@ EXPORT_SYMBOL_GPL(ata_pci_sff_activate_host);
  *     @ppi: array of port_info, must be enough for two ports
  *     @sht: scsi_host_template to use when registering the host
  *     @host_priv: host private_data
+ *     @hflag: host flags
  *
  *     This is a helper function which can be called from a driver's
  *     xxx_init_one() probe function if the hardware uses traditional
@@ -3031,8 +3058,8 @@ EXPORT_SYMBOL_GPL(ata_pci_sff_activate_host);
  *     Zero on success, negative on errno-based value on error.
  */
 int ata_pci_sff_init_one(struct pci_dev *pdev,
-                        const struct ata_port_info * const *ppi,
-                        struct scsi_host_template *sht, void *host_priv)
+                const struct ata_port_info * const *ppi,
+                struct scsi_host_template *sht, void *host_priv, int hflag)
 {
        struct device *dev = &pdev->dev;
        const struct ata_port_info *pi = NULL;
@@ -3067,6 +3094,7 @@ int ata_pci_sff_init_one(struct pci_dev *pdev,
        if (rc)
                goto out;
        host->private_data = host_priv;
+       host->flags |= hflag;
 
        pci_set_master(pdev);
        rc = ata_pci_sff_activate_host(host, ata_sff_interrupt, sht);
index d8f35fe44421914c74810481acda3d72a7839125..294f3020a78ad26e42773a6d0bb396d45ca7f13e 100644 (file)
@@ -259,7 +259,7 @@ static int pacpi_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
                        return rc;
                pcim_pin_device(pdev);
        }
-       return ata_pci_sff_init_one(pdev, ppi, &pacpi_sht, NULL);
+       return ata_pci_sff_init_one(pdev, ppi, &pacpi_sht, NULL, 0);
 }
 
 static const struct pci_device_id pacpi_pci_tbl[] = {
index 9434114b2ca8cb6f42e40d4ed2091360cd2add9e..dc61b72f751c7f8cbaf912fda1a2d57f30498fc6 100644 (file)
@@ -159,8 +159,7 @@ static void ali_fifo_control(struct ata_port *ap, struct ata_device *adev, int o
  *     ali_program_modes       -       load mode registers
  *     @ap: ALi channel to load
  *     @adev: Device the timing is for
- *     @cmd: Command timing
- *     @data: Data timing
+ *     @t: timing data
  *     @ultra: UDMA timing or zero for off
  *
  *     Loads the timing registers for cmd/data and disable UDMA if
@@ -202,8 +201,7 @@ static void ali_program_modes(struct ata_port *ap, struct ata_device *adev, stru
  *     @ap: ATA interface
  *     @adev: ATA device
  *
- *     Program the ALi registers for PIO mode. FIXME: add timings for
- *     PIO5.
+ *     Program the ALi registers for PIO mode.
  */
 
 static void ali_set_piomode(struct ata_port *ap, struct ata_device *adev)
@@ -237,7 +235,7 @@ static void ali_set_piomode(struct ata_port *ap, struct ata_device *adev)
  *     @ap: ATA interface
  *     @adev: ATA device
  *
- *     FIXME: MWDMA timings
+ *     Program the ALi registers for DMA mode.
  */
 
 static void ali_set_dmamode(struct ata_port *ap, struct ata_device *adev)
@@ -585,7 +583,7 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
                        ppi[0] = &info_20_udma;
        }
 
-       return ata_pci_sff_init_one(pdev, ppi, &ali_sht, NULL);
+       return ata_pci_sff_init_one(pdev, ppi, &ali_sht, NULL, 0);
 }
 
 #ifdef CONFIG_PM
index 567f3f72774efd2a821b2a7b24724dc3bdb38077..d95eca9c547ed332749daaac94b39a20331d0708 100644 (file)
@@ -574,7 +574,7 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
        }
 
        /* And fire it up */
-       return ata_pci_sff_init_one(pdev, ppi, &amd_sht, hpriv);
+       return ata_pci_sff_init_one(pdev, ppi, &amd_sht, hpriv, 0);
 }
 
 #ifdef CONFIG_PM
index d332cfdb0f30848d5d6dc077779b09f95dc598bd..4d066d6c30fa78bdc1a4ee08d7e66ea6da5e629b 100644 (file)
@@ -421,7 +421,7 @@ static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
 
        BUG_ON(ppi[0] == NULL);
 
-       return ata_pci_sff_init_one(pdev, ppi, &artop_sht, NULL);
+       return ata_pci_sff_init_one(pdev, ppi, &artop_sht, NULL, 0);
 }
 
 static const struct pci_device_id artop_pci_tbl[] = {
index 41c94b1ae4930b4a44e56a57e3e6dde6cd832e3b..376dd380b43c7243e214a4b74c42addfb398960f 100644 (file)
@@ -153,8 +153,8 @@ static void pata_at91_set_piomode(struct ata_port *ap, struct ata_device *adev)
        /* Compute ATA timing and set it to SMC */
        ret = ata_timing_compute(adev, adev->pio_mode, &timing, 1000, 0);
        if (ret) {
-               dev_warn(ap->dev, "Failed to compute ATA timing %d, \
-                               set PIO_0 timing\n", ret);
+               dev_warn(ap->dev, "Failed to compute ATA timing %d, "
+                        "set PIO_0 timing\n", ret);
                set_smc_timing(ap->dev, info, &initial_timing);
        } else {
                set_smc_timing(ap->dev, info, &timing);
index ae4454d4e9555aa5ce29d25708202e742759567d..cbaf2eddac6b0a1b62fe983384d14e548aff2e7d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * pata_atiixp.c       - ATI PATA for new ATA layer
  *                       (C) 2005 Red Hat Inc
- *                       (C) 2009 Bartlomiej Zolnierkiewicz
+ *                       (C) 2009-2010 Bartlomiej Zolnierkiewicz
  *
  * Based on
  *
@@ -46,6 +46,8 @@ static int atiixp_cable_detect(struct ata_port *ap)
        return ATA_CBL_PATA40;
 }
 
+static DEFINE_SPINLOCK(atiixp_lock);
+
 /**
  *     atiixp_set_pio_timing   -       set initial PIO mode data
  *     @ap: ATA interface
@@ -88,7 +90,10 @@ static void atiixp_set_pio_timing(struct ata_port *ap, struct ata_device *adev,
 
 static void atiixp_set_piomode(struct ata_port *ap, struct ata_device *adev)
 {
+       unsigned long flags;
+       spin_lock_irqsave(&atiixp_lock, flags);
        atiixp_set_pio_timing(ap, adev, adev->pio_mode - XFER_PIO_0);
+       spin_unlock_irqrestore(&atiixp_lock, flags);
 }
 
 /**
@@ -108,6 +113,9 @@ static void atiixp_set_dmamode(struct ata_port *ap, struct ata_device *adev)
        int dma = adev->dma_mode;
        int dn = 2 * ap->port_no + adev->devno;
        int wanted_pio;
+       unsigned long flags;
+
+       spin_lock_irqsave(&atiixp_lock, flags);
 
        if (adev->dma_mode >= XFER_UDMA_0) {
                u16 udma_mode_data;
@@ -145,6 +153,7 @@ static void atiixp_set_dmamode(struct ata_port *ap, struct ata_device *adev)
 
        if (adev->pio_mode != wanted_pio)
                atiixp_set_pio_timing(ap, adev, wanted_pio);
+       spin_unlock_irqrestore(&atiixp_lock, flags);
 }
 
 /**
@@ -237,7 +246,8 @@ static int atiixp_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
                if (!pci_test_config_bits(pdev, &atiixp_enable_bits[i]))
                        ppi[i] = &ata_dummy_port_info;
 
-       return ata_pci_sff_init_one(pdev, ppi, &atiixp_sht, NULL);
+       return ata_pci_sff_init_one(pdev, ppi, &atiixp_sht, NULL,
+                                               ATA_HOST_PARALLEL_SCAN);
 }
 
 static const struct pci_device_id atiixp[] = {
index 5acf9fa9b39f04a69c5552ef56d397e8bc7eefaa..6cd5d5dd9e3b04a42799c9e4f2712a82505dc769 100644 (file)
@@ -223,7 +223,7 @@ static int cmd640_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 
        cmd640_hardware_init(pdev);
 
-       return ata_pci_sff_init_one(pdev, ppi, &cmd640_sht, NULL);
+       return ata_pci_sff_init_one(pdev, ppi, &cmd640_sht, NULL, 0);
 }
 
 #ifdef CONFIG_PM
index 0efb1f58f2551f4c0d905f0298791ebb744d3425..4c81a71b8877e4262c6574e5e5eb669b88b3610d 100644 (file)
@@ -2,6 +2,7 @@
  * pata_cmd64x.c       - CMD64x PATA for new ATA layer
  *                       (C) 2005 Red Hat Inc
  *                       Alan Cox <alan@lxorguk.ukuu.org.uk>
+ *                       (C) 2009-2010 Bartlomiej Zolnierkiewicz
  *
  * Based upon
  * linux/drivers/ide/pci/cmd64x.c              Version 1.30    Sept 10, 2002
 
 enum {
        CFR             = 0x50,
-               CFR_INTR_CH0  = 0x02,
-       CNTRL           = 0x51,
-               CNTRL_DIS_RA0 = 0x40,
-               CNTRL_DIS_RA1 = 0x80,
-               CNTRL_ENA_2ND = 0x08,
+               CFR_INTR_CH0  = 0x04,
        CMDTIM          = 0x52,
        ARTTIM0         = 0x53,
        DRWTIM0         = 0x54,
@@ -53,9 +50,6 @@ enum {
                ARTTIM23_DIS_RA2  = 0x04,
                ARTTIM23_DIS_RA3  = 0x08,
                ARTTIM23_INTR_CH1 = 0x10,
-       ARTTIM2         = 0x57,
-       ARTTIM3         = 0x57,
-       DRWTIM23        = 0x58,
        DRWTIM2         = 0x58,
        BRST            = 0x59,
        DRWTIM3         = 0x5b,
@@ -63,14 +57,11 @@ enum {
        MRDMODE         = 0x71,
                MRDMODE_INTR_CH0 = 0x04,
                MRDMODE_INTR_CH1 = 0x08,
-               MRDMODE_BLK_CH0  = 0x10,
-               MRDMODE_BLK_CH1  = 0x20,
        BMIDESR0        = 0x72,
        UDIDETCR0       = 0x73,
        DTPR0           = 0x74,
        BMIDECR1        = 0x78,
        BMIDECSR        = 0x79,
-       BMIDESR1        = 0x7A,
        UDIDETCR1       = 0x7B,
        DTPR1           = 0x7C
 };
@@ -130,8 +121,14 @@ static void cmd64x_set_timing(struct ata_port *ap, struct ata_device *adev, u8 m
 
                if (pair) {
                        struct ata_timing tp;
+
                        ata_timing_compute(pair, pair->pio_mode, &tp, T, 0);
                        ata_timing_merge(&t, &tp, &t, ATA_TIMING_SETUP);
+                       if (pair->dma_mode) {
+                               ata_timing_compute(pair, pair->dma_mode,
+                                               &tp, T, 0);
+                               ata_timing_merge(&tp, &t, &t, ATA_TIMING_SETUP);
+                       }
                }
        }
 
@@ -147,7 +144,9 @@ static void cmd64x_set_timing(struct ata_port *ap, struct ata_device *adev, u8 m
        /* Now convert the clocks into values we can actually stuff into
           the chip */
 
-       if (t.recover > 1)
+       if (t.recover == 16)
+               t.recover = 0;
+       else if (t.recover > 1)
                t.recover--;
        else
                t.recover = 15;
@@ -245,7 +244,7 @@ static void cmd648_bmdma_stop(struct ata_queued_cmd *qc)
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        u8 dma_intr;
        int dma_mask = ap->port_no ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0;
-       int dma_reg = ap->port_no ? ARTTIM2 : CFR;
+       int dma_reg = ap->port_no ? ARTTIM23 : CFR;
 
        ata_bmdma_stop(qc);
 
@@ -368,7 +367,7 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
        pci_write_config_byte(pdev, UDIDETCR0, 0xF0);
 #endif
 
-       return ata_pci_sff_init_one(pdev, ppi, &cmd64x_sht, NULL);
+       return ata_pci_sff_init_one(pdev, ppi, &cmd64x_sht, NULL, 0);
 }
 
 #ifdef CONFIG_PM
index c974b05e41295e70057b5398c2d066abc68b6bf7..738ad2e14a97b245dba9f74ea423888c53c9cc3a 100644 (file)
@@ -324,7 +324,7 @@ static int cs5530_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
                ppi[1] = &info_palmax_secondary;
 
        /* Now kick off ATA set up */
-       return ata_pci_sff_init_one(pdev, ppi, &cs5530_sht, NULL);
+       return ata_pci_sff_init_one(pdev, ppi, &cs5530_sht, NULL, 0);
 }
 
 #ifdef CONFIG_PM
index 71cef9a962d4871c5bf78ba656b66f8730f1b2d7..a02e6459fdccbf85fc362295139223d0add8efd0 100644 (file)
@@ -100,7 +100,7 @@ static int cs5535_cable_detect(struct ata_port *ap)
 static void cs5535_set_piomode(struct ata_port *ap, struct ata_device *adev)
 {
        static const u16 pio_timings[5] = {
-               0xF7F4, 0x53F3, 0x13F1, 0x5131, 0x1131
+               0xF7F4, 0xF173, 0x8141, 0x5131, 0x1131
        };
        static const u16 pio_cmd_timings[5] = {
                0xF7F4, 0x53F3, 0x13F1, 0x5131, 0x1131
@@ -198,7 +198,7 @@ static int cs5535_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        rdmsr(ATAC_CH0D1_PIO, timings, dummy);
        if (CS5535_BAD_PIO(timings))
                wrmsr(ATAC_CH0D1_PIO, 0xF7F4F7F4UL, 0);
-       return ata_pci_sff_init_one(dev, ppi, &cs5535_sht, NULL);
+       return ata_pci_sff_init_one(dev, ppi, &cs5535_sht, NULL, 0);
 }
 
 static const struct pci_device_id cs5535[] = {
index ffee3978ec83513f2d4b6b4d1abb731a59479c40..914ae3506ff5639f249f0dd696ab04581af17847 100644 (file)
@@ -260,7 +260,7 @@ static int cs5536_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                return -ENODEV;
        }
 
-       return ata_pci_sff_init_one(dev, ppi, &cs5536_sht, NULL);
+       return ata_pci_sff_init_one(dev, ppi, &cs5536_sht, NULL, 0);
 }
 
 static const struct pci_device_id cs5536[] = {
index 8fb040bf7361afb8ad410d1db5f1f29b1c4af7bf..0fcc096b8daca4391f9d0d2fd188ac53979bc7e0 100644 (file)
@@ -62,14 +62,16 @@ static void cy82c693_set_piomode(struct ata_port *ap, struct ata_device *adev)
                return;
        }
 
-       time_16 = clamp_val(t.recover, 0, 15) | (clamp_val(t.active, 0, 15) << 4);
-       time_8 = clamp_val(t.act8b, 0, 15) | (clamp_val(t.rec8b, 0, 15) << 4);
+       time_16 = clamp_val(t.recover - 1, 0, 15) |
+                 (clamp_val(t.active - 1, 0, 15) << 4);
+       time_8 = clamp_val(t.act8b - 1, 0, 15) |
+                (clamp_val(t.rec8b - 1, 0, 15) << 4);
 
        if (adev->devno == 0) {
                pci_read_config_dword(pdev, CY82_IDE_ADDRSETUP, &addr);
 
                addr &= ~0x0F;  /* Mask bits */
-               addr |= clamp_val(t.setup, 0, 15);
+               addr |= clamp_val(t.setup - 1, 0, 15);
 
                pci_write_config_dword(pdev, CY82_IDE_ADDRSETUP, addr);
                pci_write_config_byte(pdev, CY82_IDE_MASTER_IOR, time_16);
@@ -79,7 +81,7 @@ static void cy82c693_set_piomode(struct ata_port *ap, struct ata_device *adev)
                pci_read_config_dword(pdev, CY82_IDE_ADDRSETUP, &addr);
 
                addr &= ~0xF0;  /* Mask bits */
-               addr |= (clamp_val(t.setup, 0, 15) << 4);
+               addr |= (clamp_val(t.setup - 1, 0, 15) << 4);
 
                pci_write_config_dword(pdev, CY82_IDE_ADDRSETUP, addr);
                pci_write_config_byte(pdev, CY82_IDE_SLAVE_IOR, time_16);
@@ -136,7 +138,7 @@ static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *i
        if (PCI_FUNC(pdev->devfn) != 1)
                return -ENODEV;
 
-       return ata_pci_sff_init_one(pdev, ppi, &cy82c693_sht, NULL);
+       return ata_pci_sff_init_one(pdev, ppi, &cy82c693_sht, NULL, 0);
 }
 
 static const struct pci_device_id cy82c693[] = {
index b2e71e6473ed2e35f01ff3d3c3bb92a67d0e2198..3bac0e0796912a669454b31f2678f1055656ab8c 100644 (file)
@@ -2,7 +2,7 @@
  *    pata_efar.c - EFAR PIIX clone controller driver
  *
  *     (C) 2005 Red Hat
- *     (C) 2009 Bartlomiej Zolnierkiewicz
+ *     (C) 2009-2010 Bartlomiej Zolnierkiewicz
  *
  *    Some parts based on ata_piix.c by Jeff Garzik and others.
  *
@@ -68,6 +68,8 @@ static int efar_cable_detect(struct ata_port *ap)
        return ATA_CBL_PATA80;
 }
 
+static DEFINE_SPINLOCK(efar_lock);
+
 /**
  *     efar_set_piomode - Initialize host controller PATA PIO timings
  *     @ap: Port whose timings we are configuring
@@ -84,7 +86,9 @@ static void efar_set_piomode (struct ata_port *ap, struct ata_device *adev)
        unsigned int pio        = adev->pio_mode - XFER_PIO_0;
        struct pci_dev *dev     = to_pci_dev(ap->host->dev);
        unsigned int idetm_port= ap->port_no ? 0x42 : 0x40;
+       unsigned long flags;
        u16 idetm_data;
+       u8 udma_enable;
        int control = 0;
 
        /*
@@ -107,6 +111,8 @@ static void efar_set_piomode (struct ata_port *ap, struct ata_device *adev)
        if (adev->class == ATA_DEV_ATA)
                control |= 4;   /* PPE */
 
+       spin_lock_irqsave(&efar_lock, flags);
+
        pci_read_config_word(dev, idetm_port, &idetm_data);
 
        /* Set PPE, IE, and TIME as appropriate */
@@ -131,6 +137,11 @@ static void efar_set_piomode (struct ata_port *ap, struct ata_device *adev)
 
        idetm_data |= 0x4000;   /* Ensure SITRE is set */
        pci_write_config_word(dev, idetm_port, idetm_data);
+
+       pci_read_config_byte(dev, 0x48, &udma_enable);
+       udma_enable &= ~(1 << (2 * ap->port_no + adev->devno));
+       pci_write_config_byte(dev, 0x48, udma_enable);
+       spin_unlock_irqrestore(&efar_lock, flags);
 }
 
 /**
@@ -151,6 +162,7 @@ static void efar_set_dmamode (struct ata_port *ap, struct ata_device *adev)
        u16 master_data;
        u8 speed                = adev->dma_mode;
        int devid               = adev->devno + 2 * ap->port_no;
+       unsigned long flags;
        u8 udma_enable;
 
        static const     /* ISP  RTC */
@@ -160,6 +172,8 @@ static void efar_set_dmamode (struct ata_port *ap, struct ata_device *adev)
                            { 2, 1 },
                            { 2, 3 }, };
 
+       spin_lock_irqsave(&efar_lock, flags);
+
        pci_read_config_word(dev, master_port, &master_data);
        pci_read_config_byte(dev, 0x48, &udma_enable);
 
@@ -217,6 +231,7 @@ static void efar_set_dmamode (struct ata_port *ap, struct ata_device *adev)
                pci_write_config_word(dev, master_port, master_data);
        }
        pci_write_config_byte(dev, 0x48, udma_enable);
+       spin_unlock_irqrestore(&efar_lock, flags);
 }
 
 static struct scsi_host_template efar_sht = {
@@ -256,13 +271,14 @@ static int efar_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                .udma_mask      = ATA_UDMA4,
                .port_ops       = &efar_ops,
        };
-       const struct ata_port_info *ppi[] = { &info, NULL };
+       const struct ata_port_info *ppi[] = { &info, &info };
 
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev,
                           "version " DRV_VERSION "\n");
 
-       return ata_pci_sff_init_one(pdev, ppi, &efar_sht, NULL);
+       return ata_pci_sff_init_one(pdev, ppi, &efar_sht, NULL,
+                                       ATA_HOST_PARALLEL_SCAN);
 }
 
 static const struct pci_device_id efar_pci_tbl[] = {
index 0bd48e8f21bdaf9dfdff8c04d44b8ca98682196e..af49bfb57247613537d6bcce2484ade417aaf49d 100644 (file)
@@ -11,9 +11,7 @@
  *
  *
  * TODO
- *     Maybe PLL mode
- *     Look into engine reset on timeout errors. Should not be
- *             required.
+ *     Look into engine reset on timeout errors. Should not be required.
  */
 
 
@@ -27,7 +25,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "pata_hpt366"
-#define DRV_VERSION    "0.6.7"
+#define DRV_VERSION    "0.6.8"
 
 struct hpt_clock {
        u8      xfer_mode;
@@ -207,17 +205,8 @@ static void hpt366_set_mode(struct ata_port *ap, struct ata_device *adev,
 {
        struct hpt_clock *clocks = ap->host->private_data;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-       u32 addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
-       u32 addr2 = 0x51 + 4 * ap->port_no;
+       u32 addr = 0x40 + 4 * adev->devno;
        u32 mask, reg;
-       u8 fast;
-
-       /* Fast interrupt prediction disable, hold off interrupt disable */
-       pci_read_config_byte(pdev, addr2, &fast);
-       if (fast & 0x80) {
-               fast &= ~0x80;
-               pci_write_config_byte(pdev, addr2, fast);
-       }
 
        /* determine timing mask and find matching clock entry */
        if (mode < XFER_MW_DMA_0)
@@ -240,9 +229,9 @@ static void hpt366_set_mode(struct ata_port *ap, struct ata_device *adev,
         * on-chip PIO FIFO/buffer (and PIO MST mode as well) to avoid
         * problems handling I/O errors later.
         */
-       pci_read_config_dword(pdev, addr1, &reg);
+       pci_read_config_dword(pdev, addr, &reg);
        reg = ((reg & ~mask) | (clocks->timing & mask)) & ~0xc0000000;
-       pci_write_config_dword(pdev, addr1, reg);
+       pci_write_config_dword(pdev, addr, reg);
 }
 
 /**
@@ -372,7 +361,7 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                        break;
        }
        /* Now kick off ATA set up */
-       return ata_pci_sff_init_one(dev, ppi, &hpt36x_sht, hpriv);
+       return ata_pci_sff_init_one(dev, ppi, &hpt36x_sht, hpriv, 0);
 }
 
 #ifdef CONFIG_PM
index 4224cfccedef951ff6c7fcc2e2f568ea546b14bb..8839307a64cf52d14301f7a52b3af99ad565c4d6 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "pata_hpt37x"
-#define DRV_VERSION    "0.6.14"
+#define DRV_VERSION    "0.6.15"
 
 struct hpt_clock {
        u8      xfer_speed;
@@ -39,25 +39,24 @@ struct hpt_chip {
 
 /* key for bus clock timings
  * bit
- * 0:3    data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
- *        DMA. cycles = value + 1
- * 4:8    data_low_time. active time of DIOW_/DIOR_ for PIO and MW
- *        DMA. cycles = value + 1
- * 9:12   cmd_high_time. inactive time of DIOW_/DIOR_ during task file
+ * 0:3    data_high_time. Inactive time of DIOW_/DIOR_ for PIO and MW DMA.
+ *        cycles = value + 1
+ * 4:8    data_low_time. Active time of DIOW_/DIOR_ for PIO and MW DMA.
+ *        cycles = value + 1
+ * 9:12   cmd_high_time. Inactive time of DIOW_/DIOR_ during task file
  *        register access.
- * 13:17  cmd_low_time. active time of DIOW_/DIOR_ during task file
+ * 13:17  cmd_low_time. Active time of DIOW_/DIOR_ during task file
  *        register access.
- * 18:21  udma_cycle_time. clock freq and clock cycles for UDMA xfer.
- *        during task file register access.
- * 22:24  pre_high_time. time to initialize 1st cycle for PIO and MW DMA
- *        xfer.
- * 25:27  cmd_pre_high_time. time to initialize 1st PIO cycle for task
+ * 18:20  udma_cycle_time. Clock cycles for UDMA xfer.
+ * 21     CLK frequency for UDMA: 0=ATA clock, 1=dual ATA clock.
+ * 22:24  pre_high_time. Time to initialize 1st cycle for PIO and MW DMA xfer.
+ * 25:27  cmd_pre_high_time. Time to initialize 1st PIO cycle for task file
  *        register access.
- * 28     UDMA enable
- * 29     DMA enable
- * 30     PIO_MST enable. if set, the chip is in bus master mode during
- *        PIO.
- * 31     FIFO enable.
+ * 28     UDMA enable.
+ * 29     DMA  enable.
+ * 30     PIO_MST enable. If set, the chip is in bus master mode during
+ *        PIO xfer.
+ * 31     FIFO enable. Only for PIO.
  */
 
 static struct hpt_clock hpt37x_timings_33[] = {
@@ -384,20 +383,12 @@ static int hpt37x_pre_reset(struct ata_link *link, unsigned long deadline)
        return ata_sff_prereset(link, deadline);
 }
 
-/**
- *     hpt370_set_piomode              -       PIO setup
- *     @ap: ATA interface
- *     @adev: device on the interface
- *
- *     Perform PIO mode setup.
- */
-
-static void hpt370_set_piomode(struct ata_port *ap, struct ata_device *adev)
+static void hpt370_set_mode(struct ata_port *ap, struct ata_device *adev,
+                           u8 mode)
 {
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        u32 addr1, addr2;
-       u32 reg;
-       u32 mode;
+       u32 reg, timing, mask;
        u8 fast;
 
        addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
@@ -409,11 +400,31 @@ static void hpt370_set_piomode(struct ata_port *ap, struct ata_device *adev)
        fast |= 0x01;
        pci_write_config_byte(pdev, addr2, fast);
 
+       /* Determine timing mask and find matching mode entry */
+       if (mode < XFER_MW_DMA_0)
+               mask = 0xcfc3ffff;
+       else if (mode < XFER_UDMA_0)
+               mask = 0x31c001ff;
+       else
+               mask = 0x303c0000;
+
+       timing = hpt37x_find_mode(ap, mode);
+
        pci_read_config_dword(pdev, addr1, &reg);
-       mode = hpt37x_find_mode(ap, adev->pio_mode);
-       mode &= 0xCFC3FFFF;     /* Leave DMA bits alone */
-       reg &= ~0xCFC3FFFF;     /* Strip timing bits */
-       pci_write_config_dword(pdev, addr1, reg | mode);
+       reg = (reg & ~mask) | (timing & mask);
+       pci_write_config_dword(pdev, addr1, reg);
+}
+/**
+ *     hpt370_set_piomode              -       PIO setup
+ *     @ap: ATA interface
+ *     @adev: device on the interface
+ *
+ *     Perform PIO mode setup.
+ */
+
+static void hpt370_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+       hpt370_set_mode(ap, adev, adev->pio_mode);
 }
 
 /**
@@ -421,33 +432,12 @@ static void hpt370_set_piomode(struct ata_port *ap, struct ata_device *adev)
  *     @ap: ATA interface
  *     @adev: Device being configured
  *
- *     Set up the channel for MWDMA or UDMA modes. Much the same as with
- *     PIO, load the mode number and then set MWDMA or UDMA flag.
+ *     Set up the channel for MWDMA or UDMA modes.
  */
 
 static void hpt370_set_dmamode(struct ata_port *ap, struct ata_device *adev)
 {
-       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-       u32 addr1, addr2;
-       u32 reg, mode, mask;
-       u8 fast;
-
-       addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
-       addr2 = 0x51 + 4 * ap->port_no;
-
-       /* Fast interrupt prediction disable, hold off interrupt disable */
-       pci_read_config_byte(pdev, addr2, &fast);
-       fast &= ~0x02;
-       fast |= 0x01;
-       pci_write_config_byte(pdev, addr2, fast);
-
-       mask = adev->dma_mode < XFER_UDMA_0 ? 0x31C001FF : 0x303C0000;
-
-       pci_read_config_dword(pdev, addr1, &reg);
-       mode = hpt37x_find_mode(ap, adev->dma_mode);
-       mode &= mask;
-       reg &= ~mask;
-       pci_write_config_dword(pdev, addr1, reg | mode);
+       hpt370_set_mode(ap, adev, adev->dma_mode);
 }
 
 /**
@@ -461,24 +451,25 @@ static void hpt370_bmdma_stop(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-       u8 dma_stat = ioread8(ap->ioaddr.bmdma_addr + 2);
-       u8 dma_cmd;
        void __iomem *bmdma = ap->ioaddr.bmdma_addr;
+       u8 dma_stat = ioread8(bmdma + ATA_DMA_STATUS);
+       u8 dma_cmd;
 
-       if (dma_stat & 0x01) {
+       if (dma_stat & ATA_DMA_ACTIVE) {
                udelay(20);
-               dma_stat = ioread8(bmdma + 2);
+               dma_stat = ioread8(bmdma + ATA_DMA_STATUS);
        }
-       if (dma_stat & 0x01) {
+       if (dma_stat & ATA_DMA_ACTIVE) {
                /* Clear the engine */
                pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
                udelay(10);
                /* Stop DMA */
-               dma_cmd = ioread8(bmdma );
-               iowrite8(dma_cmd & 0xFE, bmdma);
+               dma_cmd = ioread8(bmdma + ATA_DMA_CMD);
+               iowrite8(dma_cmd & ~ATA_DMA_START, bmdma + ATA_DMA_CMD);
                /* Clear Error */
-               dma_stat = ioread8(bmdma + 2);
-               iowrite8(dma_stat | 0x06 , bmdma + 2);
+               dma_stat = ioread8(bmdma + ATA_DMA_STATUS);
+               iowrite8(dma_stat | ATA_DMA_INTR | ATA_DMA_ERR,
+                        bmdma + ATA_DMA_STATUS);
                /* Clear the engine */
                pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
                udelay(10);
@@ -486,20 +477,12 @@ static void hpt370_bmdma_stop(struct ata_queued_cmd *qc)
        ata_bmdma_stop(qc);
 }
 
-/**
- *     hpt372_set_piomode              -       PIO setup
- *     @ap: ATA interface
- *     @adev: device on the interface
- *
- *     Perform PIO mode setup.
- */
-
-static void hpt372_set_piomode(struct ata_port *ap, struct ata_device *adev)
+static void hpt372_set_mode(struct ata_port *ap, struct ata_device *adev,
+                           u8 mode)
 {
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        u32 addr1, addr2;
-       u32 reg;
-       u32 mode;
+       u32 reg, timing, mask;
        u8 fast;
 
        addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
@@ -510,13 +493,32 @@ static void hpt372_set_piomode(struct ata_port *ap, struct ata_device *adev)
        fast &= ~0x07;
        pci_write_config_byte(pdev, addr2, fast);
 
+       /* Determine timing mask and find matching mode entry */
+       if (mode < XFER_MW_DMA_0)
+               mask = 0xcfc3ffff;
+       else if (mode < XFER_UDMA_0)
+               mask = 0x31c001ff;
+       else
+               mask = 0x303c0000;
+
+       timing = hpt37x_find_mode(ap, mode);
+
        pci_read_config_dword(pdev, addr1, &reg);
-       mode = hpt37x_find_mode(ap, adev->pio_mode);
+       reg = (reg & ~mask) | (timing & mask);
+       pci_write_config_dword(pdev, addr1, reg);
+}
+
+/**
+ *     hpt372_set_piomode              -       PIO setup
+ *     @ap: ATA interface
+ *     @adev: device on the interface
+ *
+ *     Perform PIO mode setup.
+ */
 
-       printk("Find mode for %d reports %X\n", adev->pio_mode, mode);
-       mode &= 0xCFC3FFFF;     /* Leave DMA bits alone */
-       reg &= ~0xCFC3FFFF;     /* Strip timing bits */
-       pci_write_config_dword(pdev, addr1, reg | mode);
+static void hpt372_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+       hpt372_set_mode(ap, adev, adev->pio_mode);
 }
 
 /**
@@ -524,33 +526,12 @@ static void hpt372_set_piomode(struct ata_port *ap, struct ata_device *adev)
  *     @ap: ATA interface
  *     @adev: Device being configured
  *
- *     Set up the channel for MWDMA or UDMA modes. Much the same as with
- *     PIO, load the mode number and then set MWDMA or UDMA flag.
+ *     Set up the channel for MWDMA or UDMA modes.
  */
 
 static void hpt372_set_dmamode(struct ata_port *ap, struct ata_device *adev)
 {
-       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-       u32 addr1, addr2;
-       u32 reg, mode, mask;
-       u8 fast;
-
-       addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
-       addr2 = 0x51 + 4 * ap->port_no;
-
-       /* Fast interrupt prediction disable, hold off interrupt disable */
-       pci_read_config_byte(pdev, addr2, &fast);
-       fast &= ~0x07;
-       pci_write_config_byte(pdev, addr2, fast);
-
-       mask = adev->dma_mode < XFER_UDMA_0 ? 0x31C001FF : 0x303C0000;
-
-       pci_read_config_dword(pdev, addr1, &reg);
-       mode = hpt37x_find_mode(ap, adev->dma_mode);
-       printk("Find mode for DMA %d reports %X\n", adev->dma_mode, mode);
-       mode &= mask;
-       reg &= ~mask;
-       pci_write_config_dword(pdev, addr1, reg | mode);
+       hpt372_set_mode(ap, adev, adev->dma_mode);
 }
 
 /**
@@ -1006,7 +987,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        }
 
        /* Now kick off ATA set up */
-       return ata_pci_sff_init_one(dev, ppi, &hpt37x_sht, private_data);
+       return ata_pci_sff_init_one(dev, ppi, &hpt37x_sht, private_data, 0);
 }
 
 static const struct pci_device_id hpt37x[] = {
index dd26bc73bd9aaca7b2f7839c0f71da3d7f87078d..01457b266f3d18b3aeccaa827863f37fd9ae1c85 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "pata_hpt3x2n"
-#define DRV_VERSION    "0.3.8"
+#define DRV_VERSION    "0.3.10"
 
 enum {
        HPT_PCI_FAST    =       (1 << 31),
@@ -45,25 +45,24 @@ struct hpt_chip {
 
 /* key for bus clock timings
  * bit
- * 0:3    data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
- *        DMA. cycles = value + 1
- * 4:8    data_low_time. active time of DIOW_/DIOR_ for PIO and MW
- *        DMA. cycles = value + 1
- * 9:12   cmd_high_time. inactive time of DIOW_/DIOR_ during task file
+ * 0:3    data_high_time. Inactive time of DIOW_/DIOR_ for PIO and MW DMA.
+ *        cycles = value + 1
+ * 4:8    data_low_time. Active time of DIOW_/DIOR_ for PIO and MW DMA.
+ *        cycles = value + 1
+ * 9:12   cmd_high_time. Inactive time of DIOW_/DIOR_ during task file
  *        register access.
- * 13:17  cmd_low_time. active time of DIOW_/DIOR_ during task file
+ * 13:17  cmd_low_time. Active time of DIOW_/DIOR_ during task file
  *        register access.
- * 18:21  udma_cycle_time. clock freq and clock cycles for UDMA xfer.
- *        during task file register access.
- * 22:24  pre_high_time. time to initialize 1st cycle for PIO and MW DMA
- *        xfer.
- * 25:27  cmd_pre_high_time. time to initialize 1st PIO cycle for task
+ * 18:20  udma_cycle_time. Clock cycles for UDMA xfer.
+ * 21     CLK frequency for UDMA: 0=ATA clock, 1=dual ATA clock.
+ * 22:24  pre_high_time. Time to initialize 1st cycle for PIO and MW DMA xfer.
+ * 25:27  cmd_pre_high_time. Time to initialize 1st PIO cycle for task file
  *        register access.
- * 28     UDMA enable
- * 29     DMA enable
- * 30     PIO_MST enable. if set, the chip is in bus master mode during
- *        PIO.
- * 31     FIFO enable.
+ * 28     UDMA enable.
+ * 29     DMA  enable.
+ * 30     PIO_MST enable. If set, the chip is in bus master mode during
+ *        PIO xfer.
+ * 31     FIFO enable. Only for PIO.
  */
 
 /* 66MHz DPLL clocks */
@@ -161,20 +160,12 @@ static int hpt3x2n_pre_reset(struct ata_link *link, unsigned long deadline)
        return ata_sff_prereset(link, deadline);
 }
 
-/**
- *     hpt3x2n_set_piomode             -       PIO setup
- *     @ap: ATA interface
- *     @adev: device on the interface
- *
- *     Perform PIO mode setup.
- */
-
-static void hpt3x2n_set_piomode(struct ata_port *ap, struct ata_device *adev)
+static void hpt3x2n_set_mode(struct ata_port *ap, struct ata_device *adev,
+                            u8 mode)
 {
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        u32 addr1, addr2;
-       u32 reg;
-       u32 mode;
+       u32 reg, timing, mask;
        u8 fast;
 
        addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
@@ -185,11 +176,32 @@ static void hpt3x2n_set_piomode(struct ata_port *ap, struct ata_device *adev)
        fast &= ~0x07;
        pci_write_config_byte(pdev, addr2, fast);
 
+       /* Determine timing mask and find matching mode entry */
+       if (mode < XFER_MW_DMA_0)
+               mask = 0xcfc3ffff;
+       else if (mode < XFER_UDMA_0)
+               mask = 0x31c001ff;
+       else
+               mask = 0x303c0000;
+
+       timing = hpt3x2n_find_mode(ap, mode);
+
        pci_read_config_dword(pdev, addr1, &reg);
-       mode = hpt3x2n_find_mode(ap, adev->pio_mode);
-       mode &= 0xCFC3FFFF;     /* Leave DMA bits alone */
-       reg &= ~0xCFC3FFFF;     /* Strip timing bits */
-       pci_write_config_dword(pdev, addr1, reg | mode);
+       reg = (reg & ~mask) | (timing & mask);
+       pci_write_config_dword(pdev, addr1, reg);
+}
+
+/**
+ *     hpt3x2n_set_piomode             -       PIO setup
+ *     @ap: ATA interface
+ *     @adev: device on the interface
+ *
+ *     Perform PIO mode setup.
+ */
+
+static void hpt3x2n_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+       hpt3x2n_set_mode(ap, adev, adev->pio_mode);
 }
 
 /**
@@ -197,32 +209,12 @@ static void hpt3x2n_set_piomode(struct ata_port *ap, struct ata_device *adev)
  *     @ap: ATA interface
  *     @adev: Device being configured
  *
- *     Set up the channel for MWDMA or UDMA modes. Much the same as with
- *     PIO, load the mode number and then set MWDMA or UDMA flag.
+ *     Set up the channel for MWDMA or UDMA modes.
  */
 
 static void hpt3x2n_set_dmamode(struct ata_port *ap, struct ata_device *adev)
 {
-       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-       u32 addr1, addr2;
-       u32 reg, mode, mask;
-       u8 fast;
-
-       addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
-       addr2 = 0x51 + 4 * ap->port_no;
-
-       /* Fast interrupt prediction disable, hold off interrupt disable */
-       pci_read_config_byte(pdev, addr2, &fast);
-       fast &= ~0x07;
-       pci_write_config_byte(pdev, addr2, fast);
-
-       mask = adev->dma_mode < XFER_UDMA_0 ? 0x31C001FF : 0x303C0000;
-
-       pci_read_config_dword(pdev, addr1, &reg);
-       mode = hpt3x2n_find_mode(ap, adev->dma_mode);
-       mode &= mask;
-       reg &= ~mask;
-       pci_write_config_dword(pdev, addr1, reg | mode);
+       hpt3x2n_set_mode(ap, adev, adev->dma_mode);
 }
 
 /**
@@ -544,19 +536,19 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
               pci_mhz);
        /* Set our private data up. We only need a few flags so we use
           it directly */
-       if (pci_mhz > 60) {
+       if (pci_mhz > 60)
                hpriv = (void *)(PCI66 | USE_DPLL);
-               /*
-                * On  HPT371N, if ATA clock is 66 MHz we must set bit 2 in
-                * the MISC. register to stretch the UltraDMA Tss timing.
-                * NOTE: This register is only writeable via I/O space.
-                */
-               if (dev->device == PCI_DEVICE_ID_TTI_HPT371)
-                       outb(inb(iobase + 0x9c) | 0x04, iobase + 0x9c);
-       }
+
+       /*
+        * On  HPT371N, if ATA clock is 66 MHz we must set bit 2 in
+        * the MISC. register to stretch the UltraDMA Tss timing.
+        * NOTE: This register is only writeable via I/O space.
+        */
+       if (dev->device == PCI_DEVICE_ID_TTI_HPT371)
+               outb(inb(iobase + 0x9c) | 0x04, iobase + 0x9c);
 
        /* Now kick off ATA set up */
-       return ata_pci_sff_init_one(dev, ppi, &hpt3x2n_sht, hpriv);
+       return ata_pci_sff_init_one(dev, ppi, &hpt3x2n_sht, hpriv, 0);
 }
 
 static const struct pci_device_id hpt3x2n[] = {
index 8f3325adceb3ee3b1280f03ca74b53afb3dc77ea..f971f0de88e634437251938882449d49be602bc9 100644 (file)
@@ -273,7 +273,7 @@ static int it8213_init_one (struct pci_dev *pdev, const struct pci_device_id *en
                dev_printk(KERN_DEBUG, &pdev->dev,
                           "version " DRV_VERSION "\n");
 
-       return ata_pci_sff_init_one(pdev, ppi, &it8213_sht, NULL);
+       return ata_pci_sff_init_one(pdev, ppi, &it8213_sht, NULL, 0);
 }
 
 static const struct pci_device_id it8213_pci_tbl[] = {
index edc5c1fed1508f39128d09873da1dd072805f8d1..9bde1cb5f981891536dac2656bec4fcc14d61409 100644 (file)
@@ -932,7 +932,7 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
                else
                        ppi[0] = &info_smart;
        }
-       return ata_pci_sff_init_one(pdev, ppi, &it821x_sht, NULL);
+       return ata_pci_sff_init_one(pdev, ppi, &it821x_sht, NULL, 0);
 }
 
 #ifdef CONFIG_PM
index 3a1474ac8838e02f508cffff6d6d183eac7ead92..565e01e6ac7ce169805164e52a11bb456d4fb8c8 100644 (file)
@@ -144,7 +144,7 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i
        };
        const struct ata_port_info *ppi[] = { &info, NULL };
 
-       return ata_pci_sff_init_one(pdev, ppi, &jmicron_sht, NULL);
+       return ata_pci_sff_init_one(pdev, ppi, &jmicron_sht, NULL, 0);
 }
 
 static const struct pci_device_id jmicron_pci_tbl[] = {
index 950da39cae3ded0403eac242107ce5b94999417c..e8ca02e5a71d969e4dfd852390ea8b4d119c591a 100644 (file)
@@ -147,13 +147,13 @@ static int marvell_init_one (struct pci_dev *pdev, const struct pci_device_id *i
        if (pdev->device == 0x6101)
                ppi[1] = &ata_dummy_port_info;
 
-#if defined(CONFIG_AHCI) || defined(CONFIG_AHCI_MODULE)
+#if defined(CONFIG_SATA_AHCI) || defined(CONFIG_SATA_AHCI_MODULE)
        if (!marvell_pata_active(pdev)) {
                printk(KERN_INFO DRV_NAME ": PATA port not active, deferring to AHCI driver.\n");
                return -ENODEV;
        }
 #endif
-       return ata_pci_sff_init_one(pdev, ppi, &marvell_sht, NULL);
+       return ata_pci_sff_init_one(pdev, ppi, &marvell_sht, NULL, 0);
 }
 
 static const struct pci_device_id marvell_pci_tbl[] = {
index f0d52f72f5bb0b9d88800f0db89f4cccba40069f..94f979a7f4f73f67f4d5098f38d927bbdac62ce6 100644 (file)
@@ -82,7 +82,7 @@ static int netcell_init_one (struct pci_dev *pdev, const struct pci_device_id *e
        ata_pci_bmdma_clear_simplex(pdev);
 
        /* And let the library code do the work */
-       return ata_pci_sff_init_one(pdev, port_info, &netcell_sht, NULL);
+       return ata_pci_sff_init_one(pdev, port_info, &netcell_sht, NULL, 0);
 }
 
 static const struct pci_device_id netcell_pci_tbl[] = {
index ca53fac06717b982635f52e475a1add51d79caa9..2110863bb3db7ad6329e8582c2b2cf2113f0c9d4 100644 (file)
@@ -148,7 +148,7 @@ static int ns87410_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                .port_ops = &ns87410_port_ops
        };
        const struct ata_port_info *ppi[] = { &info, NULL };
-       return ata_pci_sff_init_one(dev, ppi, &ns87410_sht, NULL);
+       return ata_pci_sff_init_one(dev, ppi, &ns87410_sht, NULL, 0);
 }
 
 static const struct pci_device_id ns87410[] = {
index 061aa1c41a4859347f51753e3b194ab20a794fe7..830431f036a1b7f4b733a9910ec30129c74cbaf4 100644 (file)
@@ -380,7 +380,7 @@ static int ns87415_init_one (struct pci_dev *pdev, const struct pci_device_id *e
 
        ns87415_fixup(pdev);
 
-       return ata_pci_sff_init_one(pdev, ppi, &ns87415_sht, NULL);
+       return ata_pci_sff_init_one(pdev, ppi, &ns87415_sht, NULL, 0);
 }
 
 static const struct pci_device_id ns87415_pci_tbl[] = {
index 9a8687db6b2d422b80ae69cd9040b1eda8cfa7cf..5f6aba7eb0dd42bdbf1c80fd77d77e48db6258ba 100644 (file)
@@ -248,7 +248,7 @@ static int oldpiix_init_one (struct pci_dev *pdev, const struct pci_device_id *e
                dev_printk(KERN_DEBUG, &pdev->dev,
                           "version " DRV_VERSION "\n");
 
-       return ata_pci_sff_init_one(pdev, ppi, &oldpiix_sht, NULL);
+       return ata_pci_sff_init_one(pdev, ppi, &oldpiix_sht, NULL, 0);
 }
 
 static const struct pci_device_id oldpiix_pci_tbl[] = {
index 99eddda2d2e5dcae041a27442d1f433a7bb58d50..00c5a02a94fc492bf5346e4454a95258ae39f26b 100644 (file)
@@ -172,7 +172,7 @@ static int opti_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
 
-       return ata_pci_sff_init_one(dev, ppi, &opti_sht, NULL);
+       return ata_pci_sff_init_one(dev, ppi, &opti_sht, NULL, 0);
 }
 
 static const struct pci_device_id opti[] = {
index 86885a445f977fdf43eb2dd5c2122b804fcaa410..76b7d12b1e8d37ed78d7196f854b8ec240780a15 100644 (file)
@@ -429,7 +429,7 @@ static int optidma_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        if (optiplus_with_udma(dev))
                ppi[0] = &info_82c700_udma;
 
-       return ata_pci_sff_init_one(dev, ppi, &optidma_sht, NULL);
+       return ata_pci_sff_init_one(dev, ppi, &optidma_sht, NULL, 0);
 }
 
 static const struct pci_device_id optidma[] = {
index 1b392c9e853134ebe5180b61c88e6451252e198d..36103531feeb0a4e5636ee3a4388b4722cd54d21 100644 (file)
@@ -136,7 +136,7 @@ static unsigned int ata_data_xfer_8bit(struct ata_device *dev,
  *
  */
  
-void pcmcia_8bit_drain_fifo(struct ata_queued_cmd *qc)
+static void pcmcia_8bit_drain_fifo(struct ata_queued_cmd *qc)
 {
        int count;
        struct ata_port *ap;
index 2f3c9bed63d99925a02d20b2e93e780340508877..9ac0897cf8b0488c3403c2db844c153d8f07f524 100644 (file)
@@ -2,7 +2,7 @@
  * pata_pdc202xx_old.c         - Promise PDC202xx PATA for new ATA layer
  *                       (C) 2005 Red Hat Inc
  *                       Alan Cox <alan@lxorguk.ukuu.org.uk>
- *                       (C) 2007,2009 Bartlomiej Zolnierkiewicz
+ *                       (C) 2007,2009,2010 Bartlomiej Zolnierkiewicz
  *
  * Based in part on linux/drivers/ide/pci/pdc202xx_old.c
  *
@@ -35,6 +35,15 @@ static int pdc2026x_cable_detect(struct ata_port *ap)
        return ATA_CBL_PATA80;
 }
 
+static void pdc202xx_exec_command(struct ata_port *ap,
+                                 const struct ata_taskfile *tf)
+{
+       DPRINTK("ata%u: cmd 0x%X\n", ap->print_id, tf->command);
+
+       iowrite8(tf->command, ap->ioaddr.command_addr);
+       ndelay(400);
+}
+
 /**
  *     pdc202xx_configure_piomode      -       set chip PIO timing
  *     @ap: ATA interface
@@ -271,6 +280,8 @@ static struct ata_port_operations pdc2024x_port_ops = {
        .cable_detect           = ata_cable_40wire,
        .set_piomode            = pdc202xx_set_piomode,
        .set_dmamode            = pdc202xx_set_dmamode,
+
+       .sff_exec_command       = pdc202xx_exec_command,
 };
 
 static struct ata_port_operations pdc2026x_port_ops = {
@@ -284,6 +295,8 @@ static struct ata_port_operations pdc2026x_port_ops = {
        .dev_config             = pdc2026x_dev_config,
 
        .port_start             = pdc2026x_port_start,
+
+       .sff_exec_command       = pdc202xx_exec_command,
 };
 
 static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
@@ -324,7 +337,7 @@ static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id
                                return -ENODEV;
                }
        }
-       return ata_pci_sff_init_one(dev, ppi, &pdc202xx_sht, NULL);
+       return ata_pci_sff_init_one(dev, ppi, &pdc202xx_sht, NULL, 0);
 }
 
 static const struct pci_device_id pdc202xx[] = {
index bfe0180f3efa37105ecbca290ed87b54c35c68ab..9816154148490f708fd22bcd0c1b62f98b3fa39b 100644 (file)
@@ -95,7 +95,7 @@ static int ata_tosh_init_one(struct pci_dev *dev, const struct pci_device_id *id
        };
        const struct ata_port_info *ppi[] = { &info, &ata_dummy_port_info };
        /* Just one port for the moment */
-       return ata_pci_sff_init_one(dev, ppi, &tosh_sht, NULL);
+       return ata_pci_sff_init_one(dev, ppi, &tosh_sht, NULL, 0);
 }
 
 static struct pci_device_id ata_tosh[] = {
index 4fd25e737d9a60a3592af247ebb9213d7a96748d..fc9602229acbe60b4353538d35b2c1dd6f776a1b 100644 (file)
@@ -227,7 +227,7 @@ static int radisys_init_one (struct pci_dev *pdev, const struct pci_device_id *e
                dev_printk(KERN_DEBUG, &pdev->dev,
                           "version " DRV_VERSION "\n");
 
-       return ata_pci_sff_init_one(pdev, ppi, &radisys_sht, NULL);
+       return ata_pci_sff_init_one(pdev, ppi, &radisys_sht, NULL, 0);
 }
 
 static const struct pci_device_id radisys_pci_tbl[] = {
index 2932998fc4c610b3505b2c3a0b07a51cef5b72d1..4a454a88aa9daacff710c47f736d28e3bec451b0 100644 (file)
@@ -95,7 +95,7 @@ static int rz1000_init_one (struct pci_dev *pdev, const struct pci_device_id *en
        printk_once(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
 
        if (rz1000_fifo_disable(pdev) == 0)
-               return ata_pci_sff_init_one(pdev, ppi, &rz1000_sht, NULL);
+               return ata_pci_sff_init_one(pdev, ppi, &rz1000_sht, NULL, 0);
 
        printk(KERN_ERR DRV_NAME ": failed to disable read-ahead on chipset..\n");
        /* Not safe to use so skip */
index 3bbed8322ecf0cb72bf57d23e0c143cd22aeca49..dfecc6f964b04eea992d410a856340d839805f81 100644 (file)
@@ -237,7 +237,7 @@ static int sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        };
        const struct ata_port_info *ppi[] = { &info, NULL };
 
-       return ata_pci_sff_init_one(dev, ppi, &sc1200_sht, NULL);
+       return ata_pci_sff_init_one(dev, ppi, &sc1200_sht, NULL, 0);
 }
 
 static const struct pci_device_id sc1200[] = {
index beaed12d50e469d4a7d79c43fd459d1346b131d2..9524d54035f70288d2bd3f114ca69b235da2a2f6 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * pata_serverworks.c  - Serverworks PATA for new ATA layer
  *                       (C) 2005 Red Hat Inc
+ *                       (C) 2010 Bartlomiej Zolnierkiewicz
  *
  * based upon
  *
@@ -253,7 +254,7 @@ static void serverworks_set_piomode(struct ata_port *ap, struct ata_device *adev
        if (serverworks_is_csb(pdev)) {
                pci_read_config_word(pdev, 0x4A, &csb5_pio);
                csb5_pio &= ~(0x0F << devbits);
-               pci_write_config_byte(pdev, 0x4A, csb5_pio | (pio << devbits));
+               pci_write_config_word(pdev, 0x4A, csb5_pio | (pio << devbits));
        }
 }
 
@@ -327,7 +328,7 @@ static int serverworks_fixup_osb4(struct pci_dev *pdev)
                pci_dev_put(isa_dev);
                return 0;
        }
-       printk(KERN_WARNING "ata_serverworks: Unable to find bridge.\n");
+       printk(KERN_WARNING DRV_NAME ": Unable to find bridge.\n");
        return -ENODEV;
 }
 
@@ -459,7 +460,7 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id
        if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
                ata_pci_bmdma_clear_simplex(pdev);
 
-       return ata_pci_sff_init_one(pdev, ppi, &serverworks_sht, NULL);
+       return ata_pci_sff_init_one(pdev, ppi, &serverworks_sht, NULL, 0);
 }
 
 #ifdef CONFIG_PM
index a2ace48a4610c2b627324088ea34c2520f068c5c..c6c589c23ffc06c84f9325c58a1a3287d8d6d3f9 100644 (file)
@@ -356,7 +356,7 @@ static int __devinit sil680_init_one(struct pci_dev *pdev,
                                 IRQF_SHARED, &sil680_sht);
 
 use_ioports:
-       return ata_pci_sff_init_one(pdev, ppi, &sil680_sht, NULL);
+       return ata_pci_sff_init_one(pdev, ppi, &sil680_sht, NULL, 0);
 }
 
 #ifdef CONFIG_PM
index 5c30d56dec84069cc85b3831f022943920c11782..b6708032f321a35cc40b8a261f95c0dbafe6b15e 100644 (file)
@@ -826,7 +826,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 
        sis_fixup(pdev, chipset);
 
-       return ata_pci_sff_init_one(pdev, ppi, &sis_sht, chipset);
+       return ata_pci_sff_init_one(pdev, ppi, &sis_sht, chipset, 0);
 }
 
 #ifdef CONFIG_PM
index 29f733c32066f1f79dfcbaf9f6635110551e16ba..733b042a746931062f26ed3a265f3c06c095cff0 100644 (file)
@@ -316,7 +316,7 @@ static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id
        val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16;
        pci_write_config_dword(dev, 0x40, val);
 
-       return ata_pci_sff_init_one(dev, ppi, &sl82c105_sht, NULL);
+       return ata_pci_sff_init_one(dev, ppi, &sl82c105_sht, NULL, 0);
 }
 
 static const struct pci_device_id sl82c105[] = {
index f1f13ff222fda913362d0e9480234055d1924961..48f50600ed2a58eccb1584a9bb1e4919affcfdd4 100644 (file)
@@ -201,7 +201,7 @@ static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
 
-       return ata_pci_sff_init_one(dev, ppi, &triflex_sht, NULL);
+       return ata_pci_sff_init_one(dev, ppi, &triflex_sht, NULL, 0);
 }
 
 static const struct pci_device_id triflex[] = {
index 0d97890af6818ee116c81b2edb474a266ed2ab54..3059ec017de3fde4c4f2100d99da286ccdf93836 100644 (file)
@@ -22,6 +22,7 @@
  *     VIA VT8233c     -       UDMA100
  *     VIA VT8235      -       UDMA133
  *     VIA VT8237      -       UDMA133
+ *     VIA VT8237A     -       UDMA133
  *     VIA VT8237S     -       UDMA133
  *     VIA VT8251      -       UDMA133
  *
 #define DRV_NAME "pata_via"
 #define DRV_VERSION "0.3.4"
 
-/*
- *     The following comes directly from Vojtech Pavlik's ide/pci/via82cxxx
- *     driver.
- */
-
 enum {
-       VIA_UDMA        = 0x007,
-       VIA_UDMA_NONE   = 0x000,
-       VIA_UDMA_33     = 0x001,
-       VIA_UDMA_66     = 0x002,
-       VIA_UDMA_100    = 0x003,
-       VIA_UDMA_133    = 0x004,
-       VIA_BAD_PREQ    = 0x010, /* Crashes if PREQ# till DDACK# set */
-       VIA_BAD_CLK66   = 0x020, /* 66 MHz clock doesn't work correctly */
-       VIA_SET_FIFO    = 0x040, /* Needs to have FIFO split set */
-       VIA_NO_UNMASK   = 0x080, /* Doesn't work with IRQ unmasking on */
-       VIA_BAD_ID      = 0x100, /* Has wrong vendor ID (0x1107) */
-       VIA_BAD_AST     = 0x200, /* Don't touch Address Setup Timing */
-       VIA_NO_ENABLES  = 0x400, /* Has no enablebits */
-       VIA_SATA_PATA   = 0x800, /* SATA/PATA combined configuration */
+       VIA_BAD_PREQ    = 0x01, /* Crashes if PREQ# till DDACK# set */
+       VIA_BAD_CLK66   = 0x02, /* 66 MHz clock doesn't work correctly */
+       VIA_SET_FIFO    = 0x04, /* Needs to have FIFO split set */
+       VIA_NO_UNMASK   = 0x08, /* Doesn't work with IRQ unmasking on */
+       VIA_BAD_ID      = 0x10, /* Has wrong vendor ID (0x1107) */
+       VIA_BAD_AST     = 0x20, /* Don't touch Address Setup Timing */
+       VIA_NO_ENABLES  = 0x40, /* Has no enablebits */
+       VIA_SATA_PATA   = 0x80, /* SATA/PATA combined configuration */
 };
 
 enum {
@@ -99,40 +89,37 @@ static const struct via_isa_bridge {
        u16 id;
        u8 rev_min;
        u8 rev_max;
-       u16 flags;
+       u8 udma_mask;
+       u8 flags;
 } via_isa_bridges[] = {
-       { "vx855",      PCI_DEVICE_ID_VIA_VX855,    0x00, 0x2f,
-         VIA_UDMA_133 | VIA_BAD_AST | VIA_SATA_PATA },
-       { "vx800",      PCI_DEVICE_ID_VIA_VX800,    0x00, 0x2f, VIA_UDMA_133 |
-       VIA_BAD_AST | VIA_SATA_PATA },
-       { "vt8261",     PCI_DEVICE_ID_VIA_8261,     0x00, 0x2f,
-         VIA_UDMA_133 | VIA_BAD_AST },
-       { "vt8237s",    PCI_DEVICE_ID_VIA_8237S,    0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
-       { "vt8251",     PCI_DEVICE_ID_VIA_8251,     0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
-       { "cx700",      PCI_DEVICE_ID_VIA_CX700,    0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_SATA_PATA },
-       { "vt6410",     PCI_DEVICE_ID_VIA_6410,     0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_NO_ENABLES },
-       { "vt6415",     PCI_DEVICE_ID_VIA_6415,     0x00, 0xff, VIA_UDMA_133 | VIA_BAD_AST | VIA_NO_ENABLES },
-       { "vt8237a",    PCI_DEVICE_ID_VIA_8237A,    0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
-       { "vt8237",     PCI_DEVICE_ID_VIA_8237,     0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
-       { "vt8235",     PCI_DEVICE_ID_VIA_8235,     0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
-       { "vt8233a",    PCI_DEVICE_ID_VIA_8233A,    0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
-       { "vt8233c",    PCI_DEVICE_ID_VIA_8233C_0,  0x00, 0x2f, VIA_UDMA_100 },
-       { "vt8233",     PCI_DEVICE_ID_VIA_8233_0,   0x00, 0x2f, VIA_UDMA_100 },
-       { "vt8231",     PCI_DEVICE_ID_VIA_8231,     0x00, 0x2f, VIA_UDMA_100 },
-       { "vt82c686b",  PCI_DEVICE_ID_VIA_82C686,   0x40, 0x4f, VIA_UDMA_100 },
-       { "vt82c686a",  PCI_DEVICE_ID_VIA_82C686,   0x10, 0x2f, VIA_UDMA_66 },
-       { "vt82c686",   PCI_DEVICE_ID_VIA_82C686,   0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
-       { "vt82c596b",  PCI_DEVICE_ID_VIA_82C596,   0x10, 0x2f, VIA_UDMA_66 },
-       { "vt82c596a",  PCI_DEVICE_ID_VIA_82C596,   0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
-       { "vt82c586b",  PCI_DEVICE_ID_VIA_82C586_0, 0x47, 0x4f, VIA_UDMA_33 | VIA_SET_FIFO },
-       { "vt82c586b",  PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x46, VIA_UDMA_33 | VIA_SET_FIFO | VIA_BAD_PREQ },
-       { "vt82c586b",  PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, VIA_UDMA_33 | VIA_SET_FIFO },
-       { "vt82c586a",  PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, VIA_UDMA_33 | VIA_SET_FIFO },
-       { "vt82c586",   PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, VIA_UDMA_NONE | VIA_SET_FIFO },
-       { "vt82c576",   PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK },
-       { "vt82c576",   PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID },
-       { "vtxxxx",     PCI_DEVICE_ID_VIA_ANON,    0x00, 0x2f,
-         VIA_UDMA_133 | VIA_BAD_AST },
+       { "vx855",      PCI_DEVICE_ID_VIA_VX855,    0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST | VIA_SATA_PATA },
+       { "vx800",      PCI_DEVICE_ID_VIA_VX800,    0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST | VIA_SATA_PATA },
+       { "vt8261",     PCI_DEVICE_ID_VIA_8261,     0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+       { "vt8237s",    PCI_DEVICE_ID_VIA_8237S,    0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+       { "vt8251",     PCI_DEVICE_ID_VIA_8251,     0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+       { "cx700",      PCI_DEVICE_ID_VIA_CX700,    0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST | VIA_SATA_PATA },
+       { "vt6410",     PCI_DEVICE_ID_VIA_6410,     0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST | VIA_NO_ENABLES },
+       { "vt6415",     PCI_DEVICE_ID_VIA_6415,     0x00, 0xff, ATA_UDMA6, VIA_BAD_AST | VIA_NO_ENABLES },
+       { "vt8237a",    PCI_DEVICE_ID_VIA_8237A,    0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+       { "vt8237",     PCI_DEVICE_ID_VIA_8237,     0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+       { "vt8235",     PCI_DEVICE_ID_VIA_8235,     0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+       { "vt8233a",    PCI_DEVICE_ID_VIA_8233A,    0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+       { "vt8233c",    PCI_DEVICE_ID_VIA_8233C_0,  0x00, 0x2f, ATA_UDMA5, },
+       { "vt8233",     PCI_DEVICE_ID_VIA_8233_0,   0x00, 0x2f, ATA_UDMA5, },
+       { "vt8231",     PCI_DEVICE_ID_VIA_8231,     0x00, 0x2f, ATA_UDMA5, },
+       { "vt82c686b",  PCI_DEVICE_ID_VIA_82C686,   0x40, 0x4f, ATA_UDMA5, },
+       { "vt82c686a",  PCI_DEVICE_ID_VIA_82C686,   0x10, 0x2f, ATA_UDMA4, },
+       { "vt82c686",   PCI_DEVICE_ID_VIA_82C686,   0x00, 0x0f, ATA_UDMA2, VIA_BAD_CLK66 },
+       { "vt82c596b",  PCI_DEVICE_ID_VIA_82C596,   0x10, 0x2f, ATA_UDMA4, },
+       { "vt82c596a",  PCI_DEVICE_ID_VIA_82C596,   0x00, 0x0f, ATA_UDMA2, VIA_BAD_CLK66 },
+       { "vt82c586b",  PCI_DEVICE_ID_VIA_82C586_0, 0x47, 0x4f, ATA_UDMA2, VIA_SET_FIFO },
+       { "vt82c586b",  PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x46, ATA_UDMA2, VIA_SET_FIFO | VIA_BAD_PREQ },
+       { "vt82c586b",  PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, ATA_UDMA2, VIA_SET_FIFO },
+       { "vt82c586a",  PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, ATA_UDMA2, VIA_SET_FIFO },
+       { "vt82c586",   PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f,      0x00, VIA_SET_FIFO },
+       { "vt82c576",   PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f,      0x00, VIA_SET_FIFO | VIA_NO_UNMASK },
+       { "vt82c576",   PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f,      0x00, VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID },
+       { "vtxxxx",     PCI_DEVICE_ID_VIA_ANON,     0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
        { NULL }
 };
 
@@ -191,10 +178,10 @@ static int via_cable_detect(struct ata_port *ap) {
                return ATA_CBL_SATA;
 
        /* Early chips are 40 wire */
-       if ((config->flags & VIA_UDMA) < VIA_UDMA_66)
+       if (config->udma_mask < ATA_UDMA4)
                return ATA_CBL_PATA40;
        /* UDMA 66 chips have only drive side logic */
-       else if ((config->flags & VIA_UDMA) < VIA_UDMA_100)
+       else if (config->udma_mask < ATA_UDMA5)
                return ATA_CBL_PATA_UNK;
        /* UDMA 100 or later */
        pci_read_config_dword(pdev, 0x50, &ata66);
@@ -229,11 +216,10 @@ static int via_pre_reset(struct ata_link *link, unsigned long deadline)
 
 
 /**
- *     via_do_set_mode -       set initial PIO mode data
+ *     via_do_set_mode -       set transfer mode data
  *     @ap: ATA interface
  *     @adev: ATA device
  *     @mode: ATA mode being programmed
- *     @tdiv: Clocks per PCI clock
  *     @set_ast: Set to program address setup
  *     @udma_type: UDMA mode/format of registers
  *
@@ -244,17 +230,27 @@ static int via_pre_reset(struct ata_link *link, unsigned long deadline)
  *     on the two channels.
  */
 
-static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev, int mode, int tdiv, int set_ast, int udma_type)
+static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev,
+                           int mode, int set_ast, int udma_type)
 {
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        struct ata_device *peer = ata_dev_pair(adev);
        struct ata_timing t, p;
-       static int via_clock = 33333;   /* Bus clock in kHZ - ought to be tunable one day */
+       static int via_clock = 33333;   /* Bus clock in kHZ */
        unsigned long T =  1000000000 / via_clock;
-       unsigned long UT = T/tdiv;
+       unsigned long UT = T;
        int ut;
        int offset = 3 - (2*ap->port_no) - adev->devno;
 
+       switch (udma_type) {
+       case ATA_UDMA4:
+               UT = T / 2; break;
+       case ATA_UDMA5:
+               UT = T / 3; break;
+       case ATA_UDMA6:
+               UT = T / 4; break;
+       }
+
        /* Calculate the timing values we require */
        ata_timing_compute(adev, mode, &t, T, UT);
 
@@ -273,7 +269,7 @@ static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev, int mo
 
                pci_read_config_byte(pdev, 0x4C, &setup);
                setup &= ~(3 << shift);
-               setup |= clamp_val(t.setup, 1, 4) << shift;     /* 1,4 or 1,4 - 1  FIXME */
+               setup |= (clamp_val(t.setup, 1, 4) - 1) << shift;
                pci_write_config_byte(pdev, 0x4C, setup);
        }
 
@@ -284,22 +280,20 @@ static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev, int mo
                ((clamp_val(t.active, 1, 16) - 1) << 4) | (clamp_val(t.recover, 1, 16) - 1));
 
        /* Load the UDMA bits according to type */
-       switch(udma_type) {
-               default:
-                       /* BUG() ? */
-                       /* fall through */
-               case 33:
-                       ut = t.udma ? (0xe0 | (clamp_val(t.udma, 2, 5) - 2)) : 0x03;
-                       break;
-               case 66:
-                       ut = t.udma ? (0xe8 | (clamp_val(t.udma, 2, 9) - 2)) : 0x0f;
-                       break;
-               case 100:
-                       ut = t.udma ? (0xe0 | (clamp_val(t.udma, 2, 9) - 2)) : 0x07;
-                       break;
-               case 133:
-                       ut = t.udma ? (0xe0 | (clamp_val(t.udma, 2, 9) - 2)) : 0x07;
-                       break;
+       switch (udma_type) {
+       case ATA_UDMA2:
+       default:
+               ut = t.udma ? (0xe0 | (clamp_val(t.udma, 2, 5) - 2)) : 0x03;
+               break;
+       case ATA_UDMA4:
+               ut = t.udma ? (0xe8 | (clamp_val(t.udma, 2, 9) - 2)) : 0x0f;
+               break;
+       case ATA_UDMA5:
+               ut = t.udma ? (0xe0 | (clamp_val(t.udma, 2, 9) - 2)) : 0x07;
+               break;
+       case ATA_UDMA6:
+               ut = t.udma ? (0xe0 | (clamp_val(t.udma, 2, 9) - 2)) : 0x07;
+               break;
        }
 
        /* Set UDMA unless device is not UDMA capable */
@@ -325,22 +319,16 @@ static void via_set_piomode(struct ata_port *ap, struct ata_device *adev)
 {
        const struct via_isa_bridge *config = ap->host->private_data;
        int set_ast = (config->flags & VIA_BAD_AST) ? 0 : 1;
-       int mode = config->flags & VIA_UDMA;
-       static u8 tclock[5] = { 1, 1, 2, 3, 4 };
-       static u8 udma[5] = { 0, 33, 66, 100, 133 };
 
-       via_do_set_mode(ap, adev, adev->pio_mode, tclock[mode], set_ast, udma[mode]);
+       via_do_set_mode(ap, adev, adev->pio_mode, set_ast, config->udma_mask);
 }
 
 static void via_set_dmamode(struct ata_port *ap, struct ata_device *adev)
 {
        const struct via_isa_bridge *config = ap->host->private_data;
        int set_ast = (config->flags & VIA_BAD_AST) ? 0 : 1;
-       int mode = config->flags & VIA_UDMA;
-       static u8 tclock[5] = { 1, 1, 2, 3, 4 };
-       static u8 udma[5] = { 0, 33, 66, 100, 133 };
 
-       via_do_set_mode(ap, adev, adev->dma_mode, tclock[mode], set_ast, udma[mode]);
+       via_do_set_mode(ap, adev, adev->dma_mode, set_ast, config->udma_mask);
 }
 
 /**
@@ -604,33 +592,29 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
        via_config_fifo(pdev, config->flags);
 
        /* Clock set up */
-       switch(config->flags & VIA_UDMA) {
-               case VIA_UDMA_NONE:
-                       if (config->flags & VIA_NO_UNMASK)
-                               ppi[0] = &via_mwdma_info_borked;
-                       else
-                               ppi[0] = &via_mwdma_info;
-                       break;
-               case VIA_UDMA_33:
-                       ppi[0] = &via_udma33_info;
-                       break;
-               case VIA_UDMA_66:
-                       ppi[0] = &via_udma66_info;
-                       /* The 66 MHz devices require we enable the clock */
-                       pci_read_config_dword(pdev, 0x50, &timing);
-                       timing |= 0x80008;
-                       pci_write_config_dword(pdev, 0x50, timing);
-                       break;
-               case VIA_UDMA_100:
-                       ppi[0] = &via_udma100_info;
-                       break;
-               case VIA_UDMA_133:
-                       ppi[0] = &via_udma133_info;
-                       break;
-               default:
-                       WARN_ON(1);
-                       return -ENODEV;
-       }
+       switch (config->udma_mask) {
+       case 0x00:
+               if (config->flags & VIA_NO_UNMASK)
+                       ppi[0] = &via_mwdma_info_borked;
+               else
+                       ppi[0] = &via_mwdma_info;
+               break;
+       case ATA_UDMA2:
+               ppi[0] = &via_udma33_info;
+               break;
+       case ATA_UDMA4:
+               ppi[0] = &via_udma66_info;
+               break;
+       case ATA_UDMA5:
+               ppi[0] = &via_udma100_info;
+               break;
+       case ATA_UDMA6:
+               ppi[0] = &via_udma133_info;
+               break;
+       default:
+               WARN_ON(1);
+               return -ENODEV;
+       }
 
        if (config->flags & VIA_BAD_CLK66) {
                /* Disable the 66MHz clock on problem devices */
@@ -640,7 +624,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
        }
 
        /* We have established the device type, now fire it up */
-       return ata_pci_sff_init_one(pdev, ppi, &via_sht, (void *)config);
+       return ata_pci_sff_init_one(pdev, ppi, &via_sht, (void *)config, 0);
 }
 
 #ifdef CONFIG_PM
@@ -667,7 +651,7 @@ static int via_reinit_one(struct pci_dev *pdev)
 
        via_config_fifo(pdev, config->flags);
 
-       if ((config->flags & VIA_UDMA) == VIA_UDMA_66) {
+       if (config->udma_mask == ATA_UDMA4) {
                /* The 66 MHz devices require we enable the clock */
                pci_read_config_dword(pdev, 0x50, &timing);
                timing |= 0x80008;
index 0c82d335c55d6c218acb9218fb54a298fd420a86..684fe04dbbb7f8200f710c578206d83bd6239030 100644 (file)
@@ -772,7 +772,7 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
        }
 
        blk_queue_segment_boundary(sdev->request_queue, segment_boundary);
-       blk_queue_max_hw_segments(sdev->request_queue, sg_tablesize);
+       blk_queue_max_segments(sdev->request_queue, sg_tablesize);
        ata_port_printk(ap, KERN_INFO,
                "DMA mask 0x%llX, segment boundary 0x%lX, hw segs %hu\n",
                (unsigned long long)*ap->host->dev->dma_mask,
index 02efd9a83d26a06df084d5fffeaf1860d7aa859f..08f65492cc81181ec5cf76e603102662ebaa92f3 100644 (file)
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_host.h>
 #include <linux/libata.h>
 
 #define DRV_NAME       "sata_via"
-#define DRV_VERSION    "2.4"
+#define DRV_VERSION    "2.6"
 
 /*
  * vt8251 is different from other sata controllers of VIA.  It has two
@@ -80,6 +82,7 @@ static int vt8251_scr_write(struct ata_link *link, unsigned int scr, u32 val);
 static void svia_tf_load(struct ata_port *ap, const struct ata_taskfile *tf);
 static void svia_noop_freeze(struct ata_port *ap);
 static int vt6420_prereset(struct ata_link *link, unsigned long deadline);
+static void vt6420_bmdma_start(struct ata_queued_cmd *qc);
 static int vt6421_pata_cable_detect(struct ata_port *ap);
 static void vt6421_set_pio_mode(struct ata_port *ap, struct ata_device *adev);
 static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev);
@@ -121,6 +124,7 @@ static struct ata_port_operations vt6420_sata_ops = {
        .inherits               = &svia_base_ops,
        .freeze                 = svia_noop_freeze,
        .prereset               = vt6420_prereset,
+       .bmdma_start            = vt6420_bmdma_start,
 };
 
 static struct ata_port_operations vt6421_pata_ops = {
@@ -377,6 +381,17 @@ static int vt6420_prereset(struct ata_link *link, unsigned long deadline)
        return 0;
 }
 
+static void vt6420_bmdma_start(struct ata_queued_cmd *qc)
+{
+       struct ata_port *ap = qc->ap;
+       if ((qc->tf.command == ATA_CMD_PACKET) &&
+           (qc->scsicmd->sc_data_direction == DMA_TO_DEVICE)) {
+               /* Prevents corruption on some ATAPI burners */
+               ata_sff_pause(ap);
+       }
+       ata_bmdma_start(qc);
+}
+
 static int vt6421_pata_cable_detect(struct ata_port *ap)
 {
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
@@ -392,14 +407,16 @@ static void vt6421_set_pio_mode(struct ata_port *ap, struct ata_device *adev)
 {
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        static const u8 pio_bits[] = { 0xA8, 0x65, 0x65, 0x31, 0x20 };
-       pci_write_config_byte(pdev, PATA_PIO_TIMING, pio_bits[adev->pio_mode - XFER_PIO_0]);
+       pci_write_config_byte(pdev, PATA_PIO_TIMING - adev->devno,
+                             pio_bits[adev->pio_mode - XFER_PIO_0]);
 }
 
 static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev)
 {
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        static const u8 udma_bits[] = { 0xEE, 0xE8, 0xE6, 0xE4, 0xE2, 0xE1, 0xE0, 0xE0 };
-       pci_write_config_byte(pdev, PATA_UDMA_TIMING, udma_bits[adev->dma_mode - XFER_UDMA_0]);
+       pci_write_config_byte(pdev, PATA_UDMA_TIMING - adev->devno,
+                             udma_bits[adev->dma_mode - XFER_UDMA_0]);
 }
 
 static const unsigned int svia_bar_sizes[] = {
index ce1fa923c414efa246aecde97b95bc7722a46879..459f1bc25a7b813e1094f54903d57852825983af 100644 (file)
@@ -2534,8 +2534,8 @@ static bool DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller)
        blk_queue_bounce_limit(RequestQueue, Controller->BounceBufferLimit);
        RequestQueue->queuedata = Controller;
        blk_queue_max_hw_segments(RequestQueue, Controller->DriverScatterGatherLimit);
-       blk_queue_max_phys_segments(RequestQueue, Controller->DriverScatterGatherLimit);
-       blk_queue_max_sectors(RequestQueue, Controller->MaxBlocksPerCommand);
+       blk_queue_max_segments(RequestQueue, Controller->DriverScatterGatherLimit);
+       blk_queue_max_hw_sectors(RequestQueue, Controller->MaxBlocksPerCommand);
        disk->queue = RequestQueue;
        sprintf(disk->disk_name, "rd/c%dd%d", Controller->ControllerNumber, n);
        disk->major = MajorNumber;
@@ -7134,7 +7134,7 @@ static struct DAC960_privdata DAC960_P_privdata = {
        .MemoryWindowSize =     DAC960_PD_RegisterWindowSize,
 };
 
-static struct pci_device_id DAC960_id_table[] = {
+static const struct pci_device_id DAC960_id_table[] = {
        {
                .vendor         = PCI_VENDOR_ID_MYLEX,
                .device         = PCI_DEVICE_ID_MYLEX_DAC960_GEM,
index 4f688434daf1a220c95050f82bd4a5c9e1a5d277..c6ddeacb77fdaa2541f55c294ec25dfa0dd7004b 100644 (file)
@@ -434,7 +434,7 @@ static struct brd_device *brd_alloc(int i)
                goto out_free_dev;
        blk_queue_make_request(brd->brd_queue, brd_make_request);
        blk_queue_ordered(brd->brd_queue, QUEUE_ORDERED_TAG, NULL);
-       blk_queue_max_sectors(brd->brd_queue, 1024);
+       blk_queue_max_hw_sectors(brd->brd_queue, 1024);
        blk_queue_bounce_limit(brd->brd_queue, BLK_BOUNCE_ANY);
 
        disk = brd->brd_disk = alloc_disk(1 << part_shift);
index 9291614ac6b7efd70adec484b6117c3de7b0974c..9e3af307aae1c3e50c506aadb776b4cda4549224 100644 (file)
@@ -257,6 +257,79 @@ static inline void removeQ(CommandList_struct *c)
        hlist_del_init(&c->list);
 }
 
+static void cciss_free_sg_chain_blocks(SGDescriptor_struct **cmd_sg_list,
+       int nr_cmds)
+{
+       int i;
+
+       if (!cmd_sg_list)
+               return;
+       for (i = 0; i < nr_cmds; i++) {
+               kfree(cmd_sg_list[i]);
+               cmd_sg_list[i] = NULL;
+       }
+       kfree(cmd_sg_list);
+}
+
+static SGDescriptor_struct **cciss_allocate_sg_chain_blocks(
+       ctlr_info_t *h, int chainsize, int nr_cmds)
+{
+       int j;
+       SGDescriptor_struct **cmd_sg_list;
+
+       if (chainsize <= 0)
+               return NULL;
+
+       cmd_sg_list = kmalloc(sizeof(*cmd_sg_list) * nr_cmds, GFP_KERNEL);
+       if (!cmd_sg_list)
+               return NULL;
+
+       /* Build up chain blocks for each command */
+       for (j = 0; j < nr_cmds; j++) {
+               /* Need a block of chainsized s/g elements. */
+               cmd_sg_list[j] = kmalloc((chainsize *
+                       sizeof(*cmd_sg_list[j])), GFP_KERNEL);
+               if (!cmd_sg_list[j]) {
+                       dev_err(&h->pdev->dev, "Cannot get memory "
+                               "for s/g chains.\n");
+                       goto clean;
+               }
+       }
+       return cmd_sg_list;
+clean:
+       cciss_free_sg_chain_blocks(cmd_sg_list, nr_cmds);
+       return NULL;
+}
+
+static void cciss_unmap_sg_chain_block(ctlr_info_t *h, CommandList_struct *c)
+{
+       SGDescriptor_struct *chain_sg;
+       u64bit temp64;
+
+       if (c->Header.SGTotal <= h->max_cmd_sgentries)
+               return;
+
+       chain_sg = &c->SG[h->max_cmd_sgentries - 1];
+       temp64.val32.lower = chain_sg->Addr.lower;
+       temp64.val32.upper = chain_sg->Addr.upper;
+       pci_unmap_single(h->pdev, temp64.val, chain_sg->Len, PCI_DMA_TODEVICE);
+}
+
+static void cciss_map_sg_chain_block(ctlr_info_t *h, CommandList_struct *c,
+       SGDescriptor_struct *chain_block, int len)
+{
+       SGDescriptor_struct *chain_sg;
+       u64bit temp64;
+
+       chain_sg = &c->SG[h->max_cmd_sgentries - 1];
+       chain_sg->Ext = CCISS_SG_CHAIN;
+       chain_sg->Len = len;
+       temp64.val = pci_map_single(h->pdev, chain_block, len,
+                               PCI_DMA_TODEVICE);
+       chain_sg->Addr.lower = temp64.val32.lower;
+       chain_sg->Addr.upper = temp64.val32.upper;
+}
+
 #include "cciss_scsi.c"                /* For SCSI tape support */
 
 static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG",
@@ -1344,26 +1417,27 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
                                kfree(buff);
                                return -ENOMEM;
                        }
-                       // Fill in the command type
+                       /* Fill in the command type */
                        c->cmd_type = CMD_IOCTL_PEND;
-                       // Fill in Command Header
-                       c->Header.ReplyQueue = 0;       // unused in simple mode
-                       if (iocommand.buf_size > 0)     // buffer to fill
+                       /* Fill in Command Header */
+                       c->Header.ReplyQueue = 0;   /* unused in simple mode */
+                       if (iocommand.buf_size > 0) /* buffer to fill */
                        {
                                c->Header.SGList = 1;
                                c->Header.SGTotal = 1;
-                       } else  // no buffers to fill
+                       } else /* no buffers to fill */
                        {
                                c->Header.SGList = 0;
                                c->Header.SGTotal = 0;
                        }
                        c->Header.LUN = iocommand.LUN_info;
-                       c->Header.Tag.lower = c->busaddr;       // use the kernel address the cmd block for tag
+                       /* use the kernel address the cmd block for tag */
+                       c->Header.Tag.lower = c->busaddr;
 
-                       // Fill in Request block
+                       /* Fill in Request block */
                        c->Request = iocommand.Request;
 
-                       // Fill in the scatter gather information
+                       /* Fill in the scatter gather information */
                        if (iocommand.buf_size > 0) {
                                temp64.val = pci_map_single(host->pdev, buff,
                                        iocommand.buf_size,
@@ -1371,7 +1445,7 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
                                c->SG[0].Addr.lower = temp64.val32.lower;
                                c->SG[0].Addr.upper = temp64.val32.upper;
                                c->SG[0].Len = iocommand.buf_size;
-                               c->SG[0].Ext = 0;       // we are not chaining
+                               c->SG[0].Ext = 0;  /* we are not chaining */
                        }
                        c->waiting = &wait;
 
@@ -1670,14 +1744,9 @@ static void cciss_softirq_done(struct request *rq)
        /* unmap the DMA mapping for all the scatter gather elements */
        for (i = 0; i < cmd->Header.SGList; i++) {
                if (curr_sg[sg_index].Ext == CCISS_SG_CHAIN) {
-                       temp64.val32.lower = cmd->SG[i].Addr.lower;
-                       temp64.val32.upper = cmd->SG[i].Addr.upper;
-                       pci_dma_sync_single_for_cpu(h->pdev, temp64.val,
-                                               cmd->SG[i].Len, ddir);
-                       pci_unmap_single(h->pdev, temp64.val,
-                                               cmd->SG[i].Len, ddir);
+                       cciss_unmap_sg_chain_block(h, cmd);
                        /* Point to the next block */
-                       curr_sg = h->cmd_sg_list[cmd->cmdindex]->sgchain;
+                       curr_sg = h->cmd_sg_list[cmd->cmdindex];
                        sg_index = 0;
                }
                temp64.val32.lower = curr_sg[sg_index].Addr.lower;
@@ -1796,12 +1865,9 @@ static int cciss_add_disk(ctlr_info_t *h, struct gendisk *disk,
        blk_queue_bounce_limit(disk->queue, h->pdev->dma_mask);
 
        /* This is a hardware imposed limit. */
-       blk_queue_max_hw_segments(disk->queue, h->maxsgentries);
-
-       /* This is a limit in the driver and could be eliminated. */
-       blk_queue_max_phys_segments(disk->queue, h->maxsgentries);
+       blk_queue_max_segments(disk->queue, h->maxsgentries);
 
-       blk_queue_max_sectors(disk->queue, h->cciss_max_sectors);
+       blk_queue_max_hw_sectors(disk->queue, h->cciss_max_sectors);
 
        blk_queue_softirq_done(disk->queue, cciss_softirq_done);
 
@@ -2425,7 +2491,7 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff,
                        c->Request.Type.Direction = XFER_READ;
                        c->Request.Timeout = 0;
                        c->Request.CDB[0] = cmd;
-                       c->Request.CDB[6] = (size >> 24) & 0xFF;        //MSB
+                       c->Request.CDB[6] = (size >> 24) & 0xFF; /* MSB */
                        c->Request.CDB[7] = (size >> 16) & 0xFF;
                        c->Request.CDB[8] = (size >> 8) & 0xFF;
                        c->Request.CDB[9] = size & 0xFF;
@@ -2694,7 +2760,7 @@ static void cciss_geometry_inquiry(int ctlr, int logvol,
                               "cciss: reading geometry failed, volume "
                               "does not support reading geometry\n");
                        drv->heads = 255;
-                       drv->sectors = 32;      // Sectors per track
+                       drv->sectors = 32;      /* Sectors per track */
                        drv->cylinders = total_size + 1;
                        drv->raid_level = RAID_UNKNOWN;
                } else {
@@ -3082,7 +3148,6 @@ static void do_cciss_request(struct request_queue *q)
        SGDescriptor_struct *curr_sg;
        drive_info_struct *drv;
        int i, dir;
-       int nseg = 0;
        int sg_index = 0;
        int chained = 0;
 
@@ -3112,19 +3177,19 @@ static void do_cciss_request(struct request_queue *q)
 
        /* fill in the request */
        drv = creq->rq_disk->private_data;
-       c->Header.ReplyQueue = 0;       // unused in simple mode
+       c->Header.ReplyQueue = 0;       /* unused in simple mode */
        /* got command from pool, so use the command block index instead */
        /* for direct lookups. */
        /* The first 2 bits are reserved for controller error reporting. */
        c->Header.Tag.lower = (c->cmdindex << 3);
        c->Header.Tag.lower |= 0x04;    /* flag for direct lookup. */
        memcpy(&c->Header.LUN, drv->LunID, sizeof(drv->LunID));
-       c->Request.CDBLen = 10; // 12 byte commands not in FW yet;
-       c->Request.Type.Type = TYPE_CMD;        // It is a command.
+       c->Request.CDBLen = 10; /* 12 byte commands not in FW yet; */
+       c->Request.Type.Type = TYPE_CMD;        /* It is a command. */
        c->Request.Type.Attribute = ATTR_SIMPLE;
        c->Request.Type.Direction =
            (rq_data_dir(creq) == READ) ? XFER_READ : XFER_WRITE;
-       c->Request.Timeout = 0; // Don't time out
+       c->Request.Timeout = 0; /* Don't time out */
        c->Request.CDB[0] =
            (rq_data_dir(creq) == READ) ? h->cciss_read : h->cciss_write;
        start_blk = blk_rq_pos(creq);
@@ -3149,13 +3214,8 @@ static void do_cciss_request(struct request_queue *q)
        for (i = 0; i < seg; i++) {
                if (((sg_index+1) == (h->max_cmd_sgentries)) &&
                        !chained && ((seg - i) > 1)) {
-                       nseg = seg - i;
-                       curr_sg[sg_index].Len = (nseg) *
-                                       sizeof(SGDescriptor_struct);
-                       curr_sg[sg_index].Ext = CCISS_SG_CHAIN;
-
                        /* Point to next chain block. */
-                       curr_sg = h->cmd_sg_list[c->cmdindex]->sgchain;
+                       curr_sg = h->cmd_sg_list[c->cmdindex];
                        sg_index = 0;
                        chained = 1;
                }
@@ -3166,31 +3226,12 @@ static void do_cciss_request(struct request_queue *q)
                curr_sg[sg_index].Addr.lower = temp64.val32.lower;
                curr_sg[sg_index].Addr.upper = temp64.val32.upper;
                curr_sg[sg_index].Ext = 0;  /* we are not chaining */
-
                ++sg_index;
        }
-
-       if (chained) {
-               int len;
-               curr_sg = c->SG;
-               sg_index = h->max_cmd_sgentries - 1;
-               len = curr_sg[sg_index].Len;
-               /* Setup pointer to next chain block.
-                * Fill out last element in current chain
-                * block with address of next chain block.
-                */
-               temp64.val = pci_map_single(h->pdev,
-                                       h->cmd_sg_list[c->cmdindex]->sgchain,
-                                       len, dir);
-
-               h->cmd_sg_list[c->cmdindex]->sg_chain_dma = temp64.val;
-               curr_sg[sg_index].Addr.lower = temp64.val32.lower;
-               curr_sg[sg_index].Addr.upper = temp64.val32.upper;
-
-               pci_dma_sync_single_for_device(h->pdev,
-                               h->cmd_sg_list[c->cmdindex]->sg_chain_dma,
-                               len, dir);
-       }
+       if (chained)
+               cciss_map_sg_chain_block(h, c, h->cmd_sg_list[c->cmdindex],
+                       (seg - (h->max_cmd_sgentries - 1)) *
+                               sizeof(SGDescriptor_struct));
 
        /* track how many SG entries we are using */
        if (seg > h->maxSG)
@@ -3209,11 +3250,11 @@ static void do_cciss_request(struct request_queue *q)
        if (likely(blk_fs_request(creq))) {
                if(h->cciss_read == CCISS_READ_10) {
                        c->Request.CDB[1] = 0;
-                       c->Request.CDB[2] = (start_blk >> 24) & 0xff;   //MSB
+                       c->Request.CDB[2] = (start_blk >> 24) & 0xff; /* MSB */
                        c->Request.CDB[3] = (start_blk >> 16) & 0xff;
                        c->Request.CDB[4] = (start_blk >> 8) & 0xff;
                        c->Request.CDB[5] = start_blk & 0xff;
-                       c->Request.CDB[6] = 0;  // (sect >> 24) & 0xff; MSB
+                       c->Request.CDB[6] = 0; /* (sect >> 24) & 0xff; MSB */
                        c->Request.CDB[7] = (blk_rq_sectors(creq) >> 8) & 0xff;
                        c->Request.CDB[8] = blk_rq_sectors(creq) & 0xff;
                        c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0;
@@ -3222,7 +3263,7 @@ static void do_cciss_request(struct request_queue *q)
 
                        c->Request.CDBLen = 16;
                        c->Request.CDB[1]= 0;
-                       c->Request.CDB[2]= (upper32 >> 24) & 0xff;      //MSB
+                       c->Request.CDB[2]= (upper32 >> 24) & 0xff; /* MSB */
                        c->Request.CDB[3]= (upper32 >> 16) & 0xff;
                        c->Request.CDB[4]= (upper32 >>  8) & 0xff;
                        c->Request.CDB[5]= upper32 & 0xff;
@@ -4240,37 +4281,10 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
                        goto clean4;
                }
        }
-       hba[i]->cmd_sg_list = kmalloc(sizeof(struct Cmd_sg_list *) *
-                                               hba[i]->nr_cmds,
-                                               GFP_KERNEL);
-       if (!hba[i]->cmd_sg_list) {
-               printk(KERN_ERR "cciss%d: Cannot get memory for "
-                       "s/g chaining.\n", i);
+       hba[i]->cmd_sg_list = cciss_allocate_sg_chain_blocks(hba[i],
+               hba[i]->chainsize, hba[i]->nr_cmds);
+       if (!hba[i]->cmd_sg_list && hba[i]->chainsize > 0)
                goto clean4;
-       }
-       /* Build up chain blocks for each command */
-       if (hba[i]->chainsize > 0) {
-               for (j = 0; j < hba[i]->nr_cmds; j++) {
-                       hba[i]->cmd_sg_list[j] =
-                                       kmalloc(sizeof(struct Cmd_sg_list),
-                                                       GFP_KERNEL);
-                       if (!hba[i]->cmd_sg_list[j]) {
-                               printk(KERN_ERR "cciss%d: Cannot get memory "
-                                       "for chain block.\n", i);
-                               goto clean4;
-                       }
-                       /* Need a block of chainsized s/g elements. */
-                       hba[i]->cmd_sg_list[j]->sgchain =
-                                       kmalloc((hba[i]->chainsize *
-                                               sizeof(SGDescriptor_struct)),
-                                               GFP_KERNEL);
-                       if (!hba[i]->cmd_sg_list[j]->sgchain) {
-                               printk(KERN_ERR "cciss%d: Cannot get memory "
-                                       "for s/g chains\n", i);
-                               goto clean4;
-                       }
-               }
-       }
 
        spin_lock_init(&hba[i]->lock);
 
@@ -4329,16 +4343,7 @@ clean4:
        for (k = 0; k < hba[i]->nr_cmds; k++)
                kfree(hba[i]->scatter_list[k]);
        kfree(hba[i]->scatter_list);
-       /* Only free up extra s/g lists if controller supports them */
-       if (hba[i]->chainsize > 0) {
-               for (j = 0; j < hba[i]->nr_cmds; j++) {
-                       if (hba[i]->cmd_sg_list[j]) {
-                               kfree(hba[i]->cmd_sg_list[j]->sgchain);
-                               kfree(hba[i]->cmd_sg_list[j]);
-                       }
-               }
-               kfree(hba[i]->cmd_sg_list);
-       }
+       cciss_free_sg_chain_blocks(hba[i]->cmd_sg_list, hba[i]->nr_cmds);
        if (hba[i]->cmd_pool)
                pci_free_consistent(hba[i]->pdev,
                                    hba[i]->nr_cmds * sizeof(CommandList_struct),
@@ -4456,16 +4461,7 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev)
        for (j = 0; j < hba[i]->nr_cmds; j++)
                kfree(hba[i]->scatter_list[j]);
        kfree(hba[i]->scatter_list);
-       /* Only free up extra s/g lists if controller supports them */
-       if (hba[i]->chainsize > 0) {
-               for (j = 0; j < hba[i]->nr_cmds; j++) {
-                       if (hba[i]->cmd_sg_list[j]) {
-                               kfree(hba[i]->cmd_sg_list[j]->sgchain);
-                               kfree(hba[i]->cmd_sg_list[j]);
-                       }
-               }
-               kfree(hba[i]->cmd_sg_list);
-       }
+       cciss_free_sg_chain_blocks(hba[i]->cmd_sg_list, hba[i]->nr_cmds);
        /*
         * Deliberately omit pci_disable_device(): it does something nasty to
         * Smart Array controllers that pci_enable_device does not undo
@@ -4498,7 +4494,7 @@ static int __init cciss_init(void)
         * boundary. Given that we use pci_alloc_consistent() to allocate an
         * array of them, the size must be a multiple of 8 bytes.
         */
-       BUILD_BUG_ON(sizeof(CommandList_struct) % 8);
+       BUILD_BUG_ON(sizeof(CommandList_struct) % COMMANDLIST_ALIGNMENT);
 
        printk(KERN_INFO DRIVER_NAME "\n");
 
index 1d95db254069d5ef84d8d5efb2a47887dfd86e32..c5d411174db0fb282d019a391c94f723513a84ae 100644 (file)
@@ -55,18 +55,12 @@ typedef struct _drive_info_struct
        char device_initialized;     /* indicates whether dev is initialized */
 } drive_info_struct;
 
-struct Cmd_sg_list {
-       SGDescriptor_struct     *sgchain;
-       dma_addr_t              sg_chain_dma;
-       int                     chain_block_size;
-};
-
 struct ctlr_info
 {
        int     ctlr;
        char    devname[8];
        char    *product_name;
-       char    firm_ver[4]; // Firmware version 
+       char    firm_ver[4]; /* Firmware version */
        struct pci_dev *pdev;
        __u32   board_id;
        void __iomem *vaddr;
@@ -89,7 +83,7 @@ struct ctlr_info
        int     maxsgentries;
        int     chainsize;
        int     max_cmd_sgentries;
-       struct Cmd_sg_list **cmd_sg_list;
+       SGDescriptor_struct **cmd_sg_list;
 
 #      define DOORBELL_INT     0
 #      define PERF_MODE_INT    1
@@ -103,7 +97,7 @@ struct ctlr_info
        BYTE    cciss_write;
        BYTE    cciss_read_capacity;
 
-       // information about each logical volume
+       /* information about each logical volume */
        drive_info_struct *drv[CISS_MAX_LUN];
 
        struct access_method access;
@@ -116,7 +110,7 @@ struct ctlr_info
        unsigned int maxSG;
        spinlock_t lock;
 
-       //* pointers to command and error info pool */ 
+       /* pointers to command and error info pool */
        CommandList_struct      *cmd_pool;
        dma_addr_t              cmd_pool_dhandle; 
        ErrorInfo_struct        *errinfo_pool;
@@ -134,12 +128,10 @@ struct ctlr_info
        */
        int                     next_to_run;
 
-       // Disk structures we need to pass back
+       /* Disk structures we need to pass back */
        struct gendisk   *gendisk[CISS_MAX_LUN];
 #ifdef CONFIG_CISS_SCSI_TAPE
-       void *scsi_ctlr; /* ptr to structure containing scsi related stuff */
-       /* list of block side commands the scsi error handling sucked up */
-       /* and saved for later processing */
+       struct cciss_scsi_adapter_data_t *scsi_ctlr;
 #endif
        unsigned char alive;
        struct list_head scan_list;
@@ -315,4 +307,3 @@ struct board_type {
 #define CCISS_LOCK(i)  (&hba[i]->lock)
 
 #endif /* CCISS_H */
-
index 6afa700890fffc5d01cf81c83151e487b5c92e1f..e624ff959cb68d572c9826612255a9f84b9cf796 100644 (file)
@@ -1,31 +1,16 @@
 #ifndef CCISS_CMD_H
 #define CCISS_CMD_H
-//###########################################################################
-//DEFINES
-//###########################################################################
+
+#include <linux/cciss_defs.h>
+
+/* DEFINES */
 #define CISS_VERSION "1.00"
 
-//general boundary definitions
-#define SENSEINFOBYTES          32//note that this value may vary between host implementations
+/* general boundary definitions */
 #define MAXSGENTRIES            32
 #define CCISS_SG_CHAIN          0x80000000
 #define MAXREPLYQS              256
 
-//Command Status value
-#define CMD_SUCCESS             0x0000
-#define CMD_TARGET_STATUS       0x0001
-#define CMD_DATA_UNDERRUN       0x0002
-#define CMD_DATA_OVERRUN        0x0003
-#define CMD_INVALID             0x0004
-#define CMD_PROTOCOL_ERR        0x0005
-#define CMD_HARDWARE_ERR        0x0006
-#define CMD_CONNECTION_LOST     0x0007
-#define CMD_ABORTED             0x0008
-#define CMD_ABORT_FAILED        0x0009
-#define CMD_UNSOLICITED_ABORT   0x000A
-#define CMD_TIMEOUT             0x000B
-#define CMD_UNABORTABLE                0x000C
-
 /* Unit Attentions ASC's as defined for the MSA2012sa */
 #define POWER_OR_RESET                 0x29
 #define STATE_CHANGED                  0x2a
 #define ASYM_ACCESS_CHANGED            0x06
 #define LUN_CAPACITY_CHANGED           0x09
 
-//transfer direction
-#define XFER_NONE               0x00
-#define XFER_WRITE              0x01
-#define XFER_READ               0x02
-#define XFER_RSVD               0x03
-
-//task attribute
-#define ATTR_UNTAGGED           0x00
-#define ATTR_SIMPLE             0x04
-#define ATTR_HEADOFQUEUE        0x05
-#define ATTR_ORDERED            0x06
-#define ATTR_ACA                0x07
-
-//cdb type
-#define TYPE_CMD                               0x00
-#define TYPE_MSG                               0x01
-
-//config space register offsets
+/* config space register offsets */
 #define CFG_VENDORID            0x00
 #define CFG_DEVICEID            0x02
 #define CFG_I2OBAR              0x10
 #define CFG_MEM1BAR             0x14
 
-//i2o space register offsets
+/* i2o space register offsets */
 #define I2O_IBDB_SET            0x20
 #define I2O_IBDB_CLEAR          0x70
 #define I2O_INT_STATUS          0x30
@@ -81,7 +49,7 @@
 #define I2O_OBPOST_Q            0x44
 #define I2O_DMA1_CFG           0x214
 
-//Configuration Table
+/* Configuration Table */
 #define CFGTBL_ChangeReq        0x00000001l
 #define CFGTBL_AccCmds          0x00000001l
 
@@ -103,24 +71,17 @@ typedef union _u64bit
    __u64       val;
 } u64bit;
 
-// Type defs used in the following structs
-#define BYTE __u8
-#define WORD __u16
-#define HWORD __u16
-#define DWORD __u32
+/* Type defs used in the following structs */
 #define QWORD vals32 
 
-//###########################################################################
-//STRUCTURES
-//###########################################################################
-#define CISS_MAX_LUN   1024
+/* STRUCTURES */
 #define CISS_MAX_PHYS_LUN      1024
-// SCSI-3 Cmmands 
+/* SCSI-3 Cmmands */
 
 #pragma pack(1)        
 
 #define CISS_INQUIRY 0x12
-//Date returned
+/* Date returned */
 typedef struct _InquiryData_struct
 {
   BYTE data_byte[36];
@@ -128,7 +89,7 @@ typedef struct _InquiryData_struct
 
 #define CISS_REPORT_LOG 0xc2    /* Report Logical LUNs */
 #define CISS_REPORT_PHYS 0xc3   /* Report Physical LUNs */
-// Data returned
+/* Data returned */
 typedef struct _ReportLUNdata_struct
 {
   BYTE LUNListLength[4];
@@ -139,8 +100,8 @@ typedef struct _ReportLUNdata_struct
 #define CCISS_READ_CAPACITY 0x25 /* Read Capacity */ 
 typedef struct _ReadCapdata_struct
 {
-  BYTE total_size[4];  // Total size in blocks
-  BYTE block_size[4];  // Size of blocks in bytes
+  BYTE total_size[4];  /* Total size in blocks */
+  BYTE block_size[4];  /* Size of blocks in bytes */
 } ReadCapdata_struct;
 
 #define CCISS_READ_CAPACITY_16 0x9e /* Read Capacity 16 */
@@ -172,52 +133,13 @@ typedef struct _ReadCapdata_struct_16
 #define CDB_LEN10      10
 #define CDB_LEN16      16
 
-// BMIC commands 
+/* BMIC commands */
 #define BMIC_READ 0x26
 #define BMIC_WRITE 0x27
 #define BMIC_CACHE_FLUSH 0xc2
-#define CCISS_CACHE_FLUSH 0x01 //C2 was already being used by CCISS
-
-//Command List Structure
-typedef union _SCSI3Addr_struct {
-   struct {
-    BYTE Dev;
-    BYTE Bus:6;
-    BYTE Mode:2;        // b00
-  } PeripDev;
-   struct {
-    BYTE DevLSB;
-    BYTE DevMSB:6;
-    BYTE Mode:2;        // b01
-  } LogDev;
-   struct {
-    BYTE Dev:5;
-    BYTE Bus:3;
-    BYTE Targ:6;
-    BYTE Mode:2;        // b10
-  } LogUnit;
-} SCSI3Addr_struct;
-
-typedef struct _PhysDevAddr_struct {
-  DWORD             TargetId:24;
-  DWORD             Bus:6;
-  DWORD             Mode:2;
-  SCSI3Addr_struct  Target[2]; //2 level target device addr
-} PhysDevAddr_struct;
-  
-typedef struct _LogDevAddr_struct {
-  DWORD            VolId:30;
-  DWORD            Mode:2;
-  BYTE             reserved[4];
-} LogDevAddr_struct;
-
-typedef union _LUNAddr_struct {
-  BYTE               LunAddrBytes[8];
-  SCSI3Addr_struct   SCSI3Lun[4];
-  PhysDevAddr_struct PhysDev;
-  LogDevAddr_struct  LogDev;
-} LUNAddr_struct;
+#define CCISS_CACHE_FLUSH 0x01 /* C2 was already being used by CCISS */
 
+/* Command List Structure */
 #define CTLR_LUNID "\0\0\0\0\0\0\0\0"
 
 typedef struct _CommandListHeader_struct {
@@ -227,16 +149,6 @@ typedef struct _CommandListHeader_struct {
   QWORD             Tag;
   LUNAddr_struct    LUN;
 } CommandListHeader_struct;
-typedef struct _RequestBlock_struct {
-  BYTE   CDBLen;
-  struct {
-    BYTE Type:3;
-    BYTE Attribute:3;
-    BYTE Direction:2;
-  } Type;
-  HWORD  Timeout;
-  BYTE   CDB[16];
-} RequestBlock_struct;
 typedef struct _ErrDescriptor_struct {
   QWORD  Addr;
   DWORD  Len;
@@ -247,28 +159,6 @@ typedef struct _SGDescriptor_struct {
   DWORD  Ext;
 } SGDescriptor_struct;
 
-typedef union _MoreErrInfo_struct{
-  struct {
-    BYTE  Reserved[3];
-    BYTE  Type;
-    DWORD ErrorInfo;
-  }Common_Info;
-  struct{
-    BYTE  Reserved[2];
-    BYTE  offense_size;//size of offending entry
-    BYTE  offense_num; //byte # of offense 0-base
-    DWORD offense_value;
-  }Invalid_Cmd;
-}MoreErrInfo_struct;
-typedef struct _ErrorInfo_struct {
-  BYTE               ScsiStatus;
-  BYTE               SenseLen;
-  HWORD              CommandStatus;
-  DWORD              ResidualCnt;
-  MoreErrInfo_struct MoreErrInfo;
-  BYTE               SenseInfo[SENSEINFOBYTES];
-} ErrorInfo_struct;
-
 /* Command types */
 #define CMD_RWREQ       0x00
 #define CMD_IOCTL_PEND  0x01
@@ -277,10 +167,18 @@ typedef struct _ErrorInfo_struct {
 #define CMD_MSG_TIMEOUT 0x05
 #define CMD_MSG_STALE  0xff
 
-/* This structure needs to be divisible by 8 for new
- * indexing method.
+/* This structure needs to be divisible by COMMANDLIST_ALIGNMENT
+ * because low bits of the address are used to to indicate that
+ * whether the tag contains an index or an address.  PAD_32 and
+ * PAD_64 can be adjusted independently as needed for 32-bit
+ * and 64-bits systems.
  */
-#define PADSIZE (sizeof(long) - 4)
+#define COMMANDLIST_ALIGNMENT (8)
+#define IS_64_BIT ((sizeof(long) - 4)/4)
+#define IS_32_BIT (!IS_64_BIT)
+#define PAD_32 (0)
+#define PAD_64 (4)
+#define PADSIZE (IS_32_BIT * PAD_32 + IS_64_BIT * PAD_64)
 typedef struct _CommandList_struct {
   CommandListHeader_struct Header;
   RequestBlock_struct      Request;
@@ -300,7 +198,7 @@ typedef struct _CommandList_struct {
   char   pad[PADSIZE];
 } CommandList_struct;
 
-//Configuration Table Structure
+/* Configuration Table Structure */
 typedef struct _HostWrite_struct {
   DWORD TransportRequest;
   DWORD Reserved;
@@ -326,4 +224,4 @@ typedef struct _CfgTable_struct {
   DWORD            MaxPhysicalDrivesPerLogicalUnit;
 } CfgTable_struct;
 #pragma pack()  
-#endif // CCISS_CMD_H
+#endif /* CCISS_CMD_H */
index 5d0e46dc36320f701f816f825ca3563bedf6d3e9..e1d0e2cfec72aaae4d332e693005d5d30833e8ab 100644 (file)
@@ -84,7 +84,6 @@ static struct scsi_host_template cciss_driver_template = {
        .queuecommand           = cciss_scsi_queue_command,
        .can_queue              = SCSI_CCISS_CAN_QUEUE,
        .this_id                = 7,
-       .sg_tablesize           = MAXSGENTRIES,
        .cmd_per_lun            = 1,
        .use_clustering         = DISABLE_CLUSTERING,
        /* Can't have eh_bus_reset_handler or eh_host_reset_handler for cciss */
@@ -93,11 +92,16 @@ static struct scsi_host_template cciss_driver_template = {
 };
 
 #pragma pack(1)
+
+#define SCSI_PAD_32 0
+#define SCSI_PAD_64 0
+
 struct cciss_scsi_cmd_stack_elem_t {
        CommandList_struct cmd;
        ErrorInfo_struct Err;
        __u32 busaddr;
-       __u32 pad;
+       int cmdindex;
+       u8 pad[IS_32_BIT * SCSI_PAD_32 + IS_64_BIT * SCSI_PAD_64];
 };
 
 #pragma pack()
@@ -118,16 +122,15 @@ struct cciss_scsi_cmd_stack_t {
 struct cciss_scsi_adapter_data_t {
        struct Scsi_Host *scsi_host;
        struct cciss_scsi_cmd_stack_t cmd_stack;
+       SGDescriptor_struct **cmd_sg_list;
        int registered;
        spinlock_t lock; // to protect ccissscsi[ctlr]; 
 };
 
 #define CPQ_TAPE_LOCK(ctlr, flags) spin_lock_irqsave( \
-       &(((struct cciss_scsi_adapter_data_t *) \
-       hba[ctlr]->scsi_ctlr)->lock), flags);
+       &hba[ctlr]->scsi_ctlr->lock, flags);
 #define CPQ_TAPE_UNLOCK(ctlr, flags) spin_unlock_irqrestore( \
-       &(((struct cciss_scsi_adapter_data_t *) \
-       hba[ctlr]->scsi_ctlr)->lock), flags);
+       &hba[ctlr]->scsi_ctlr->lock, flags);
 
 static CommandList_struct *
 scsi_cmd_alloc(ctlr_info_t *h)
@@ -143,7 +146,7 @@ scsi_cmd_alloc(ctlr_info_t *h)
        struct cciss_scsi_cmd_stack_t *stk;
        u64bit temp64;
 
-       sa = (struct cciss_scsi_adapter_data_t *) h->scsi_ctlr;
+       sa = h->scsi_ctlr;
        stk = &sa->cmd_stack; 
 
        if (stk->top < 0) 
@@ -154,6 +157,7 @@ scsi_cmd_alloc(ctlr_info_t *h)
        memset(&c->Err, 0, sizeof(c->Err));
        /* set physical addr of cmd and addr of scsi parameters */
        c->cmd.busaddr = c->busaddr; 
+       c->cmd.cmdindex = c->cmdindex;
        /* (__u32) (stk->cmd_pool_handle + 
                (sizeof(struct cciss_scsi_cmd_stack_elem_t)*stk->top)); */
 
@@ -182,7 +186,7 @@ scsi_cmd_free(ctlr_info_t *h, CommandList_struct *cmd)
        struct cciss_scsi_adapter_data_t *sa;
        struct cciss_scsi_cmd_stack_t *stk;
 
-       sa = (struct cciss_scsi_adapter_data_t *) h->scsi_ctlr;
+       sa = h->scsi_ctlr;
        stk = &sa->cmd_stack; 
        if (stk->top >= CMD_STACK_SIZE) {
                printk("cciss: scsi_cmd_free called too many times.\n");
@@ -199,24 +203,31 @@ scsi_cmd_stack_setup(int ctlr, struct cciss_scsi_adapter_data_t *sa)
        struct cciss_scsi_cmd_stack_t *stk;
        size_t size;
 
+       sa->cmd_sg_list = cciss_allocate_sg_chain_blocks(hba[ctlr],
+               hba[ctlr]->chainsize, CMD_STACK_SIZE);
+       if (!sa->cmd_sg_list && hba[ctlr]->chainsize > 0)
+               return -ENOMEM;
+
        stk = &sa->cmd_stack; 
        size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE;
 
-       // pci_alloc_consistent guarantees 32-bit DMA address will
-       // be used
-
+       /* Check alignment, see cciss_cmd.h near CommandList_struct def. */
+       BUILD_BUG_ON((sizeof(*stk->pool) % COMMANDLIST_ALIGNMENT) != 0);
+       /* pci_alloc_consistent guarantees 32-bit DMA address will be used */
        stk->pool = (struct cciss_scsi_cmd_stack_elem_t *)
                pci_alloc_consistent(hba[ctlr]->pdev, size, &stk->cmd_pool_handle);
 
        if (stk->pool == NULL) {
-               printk("stk->pool is null\n");
-               return -1;
+               cciss_free_sg_chain_blocks(sa->cmd_sg_list, CMD_STACK_SIZE);
+               sa->cmd_sg_list = NULL;
+               return -ENOMEM;
        }
 
        for (i=0; i<CMD_STACK_SIZE; i++) {
                stk->elem[i] = &stk->pool[i];
                stk->elem[i]->busaddr = (__u32) (stk->cmd_pool_handle + 
                        (sizeof(struct cciss_scsi_cmd_stack_elem_t) * i));
+               stk->elem[i]->cmdindex = i;
        }
        stk->top = CMD_STACK_SIZE-1;
        return 0;
@@ -229,7 +240,7 @@ scsi_cmd_stack_free(int ctlr)
        struct cciss_scsi_cmd_stack_t *stk;
        size_t size;
 
-       sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr;
+       sa = hba[ctlr]->scsi_ctlr;
        stk = &sa->cmd_stack; 
        if (stk->top != CMD_STACK_SIZE-1) {
                printk( "cciss: %d scsi commands are still outstanding.\n",
@@ -241,6 +252,7 @@ scsi_cmd_stack_free(int ctlr)
 
        pci_free_consistent(hba[ctlr]->pdev, size, stk->pool, stk->cmd_pool_handle);
        stk->pool = NULL;
+       cciss_free_sg_chain_blocks(sa->cmd_sg_list, CMD_STACK_SIZE);
 }
 
 #if 0
@@ -530,8 +542,7 @@ adjust_cciss_scsi_table(int ctlr, int hostno,
        CPQ_TAPE_LOCK(ctlr, flags);
 
        if (hostno != -1)  /* if it's not the first time... */
-               sh = ((struct cciss_scsi_adapter_data_t *)
-                       hba[ctlr]->scsi_ctlr)->scsi_host;
+               sh = hba[ctlr]->scsi_ctlr->scsi_host;
 
        /* find any devices in ccissscsi[] that are not in 
           sd[] and remove them from ccissscsi[] */
@@ -702,7 +713,7 @@ cciss_scsi_setup(int cntl_num)
                kfree(shba);
                shba = NULL;
        }
-       hba[cntl_num]->scsi_ctlr = (void *) shba;
+       hba[cntl_num]->scsi_ctlr = shba;
        return;
 }
 
@@ -725,6 +736,8 @@ complete_scsi_command( CommandList_struct *cp, int timeout, __u32 tag)
        ctlr = hba[cp->ctlr];
 
        scsi_dma_unmap(cmd);
+       if (cp->Header.SGTotal > ctlr->max_cmd_sgentries)
+               cciss_unmap_sg_chain_block(ctlr, cp);
 
        cmd->result = (DID_OK << 16);           /* host byte */
        cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */
@@ -847,9 +860,10 @@ cciss_scsi_detect(int ctlr)
        sh->io_port = 0;        // good enough?  FIXME, 
        sh->n_io_port = 0;      // I don't think we use these two...
        sh->this_id = SELF_SCSI_ID;  
+       sh->sg_tablesize = hba[ctlr]->maxsgentries;
 
        ((struct cciss_scsi_adapter_data_t *) 
-               hba[ctlr]->scsi_ctlr)->scsi_host = (void *) sh;
+               hba[ctlr]->scsi_ctlr)->scsi_host = sh;
        sh->hostdata[0] = (unsigned long) hba[ctlr];
        sh->irq = hba[ctlr]->intr[SIMPLE_MODE_INT];
        sh->unique_id = sh->irq;
@@ -1364,34 +1378,54 @@ cciss_scsi_proc_info(struct Scsi_Host *sh,
    dma mapping  and fills in the scatter gather entries of the 
    cciss command, cp. */
 
-static void
-cciss_scatter_gather(struct pci_dev *pdev, 
-               CommandList_struct *cp, 
-               struct scsi_cmnd *cmd)
+static void cciss_scatter_gather(ctlr_info_t *h, CommandList_struct *cp,
+       struct scsi_cmnd *cmd)
 {
        unsigned int len;
        struct scatterlist *sg;
        __u64 addr64;
-       int use_sg, i;
-
-       BUG_ON(scsi_sg_count(cmd) > MAXSGENTRIES);
-
-       use_sg = scsi_dma_map(cmd);
-       if (use_sg) {   /* not too many addrs? */
-               scsi_for_each_sg(cmd, sg, use_sg, i) {
+       int request_nsgs, i, chained, sg_index;
+       struct cciss_scsi_adapter_data_t *sa = h->scsi_ctlr;
+       SGDescriptor_struct *curr_sg;
+
+       BUG_ON(scsi_sg_count(cmd) > h->maxsgentries);
+
+       chained = 0;
+       sg_index = 0;
+       curr_sg = cp->SG;
+       request_nsgs = scsi_dma_map(cmd);
+       if (request_nsgs) {
+               scsi_for_each_sg(cmd, sg, request_nsgs, i) {
+                       if (sg_index + 1 == h->max_cmd_sgentries &&
+                               !chained && request_nsgs - i > 1) {
+                               chained = 1;
+                               sg_index = 0;
+                               curr_sg = sa->cmd_sg_list[cp->cmdindex];
+                       }
                        addr64 = (__u64) sg_dma_address(sg);
                        len  = sg_dma_len(sg);
-                       cp->SG[i].Addr.lower =
-                               (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF);
-                       cp->SG[i].Addr.upper =
-                               (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF);
-                       cp->SG[i].Len = len;
-                       cp->SG[i].Ext = 0;  // we are not chaining
+                       curr_sg[sg_index].Addr.lower =
+                               (__u32) (addr64 & 0x0FFFFFFFFULL);
+                       curr_sg[sg_index].Addr.upper =
+                               (__u32) ((addr64 >> 32) & 0x0FFFFFFFFULL);
+                       curr_sg[sg_index].Len = len;
+                       curr_sg[sg_index].Ext = 0;
+                       ++sg_index;
                }
+               if (chained)
+                       cciss_map_sg_chain_block(h, cp,
+                               sa->cmd_sg_list[cp->cmdindex],
+                               (request_nsgs - (h->max_cmd_sgentries - 1)) *
+                                       sizeof(SGDescriptor_struct));
        }
-
-       cp->Header.SGList = (__u8) use_sg;   /* no. SGs contig in this cmd */
-       cp->Header.SGTotal = (__u16) use_sg; /* total sgs in this cmd list */
+       /* track how many SG entries we are using */
+       if (request_nsgs > h->maxSG)
+               h->maxSG = request_nsgs;
+       cp->Header.SGTotal = (__u8) request_nsgs + chained;
+       if (request_nsgs > h->max_cmd_sgentries)
+               cp->Header.SGList = h->max_cmd_sgentries;
+       else
+               cp->Header.SGList = cp->Header.SGTotal;
        return;
 }
 
@@ -1399,7 +1433,7 @@ cciss_scatter_gather(struct pci_dev *pdev,
 static int
 cciss_scsi_queue_command (struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
 {
-       ctlr_info_t **c;
+       ctlr_info_t *c;
        int ctlr, rc;
        unsigned char scsi3addr[8];
        CommandList_struct *cp;
@@ -1407,8 +1441,8 @@ cciss_scsi_queue_command (struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd
 
        // Get the ptr to our adapter structure (hba[i]) out of cmd->host.
        // We violate cmd->host privacy here.  (Is there another way?)
-       c = (ctlr_info_t **) &cmd->device->host->hostdata[0];   
-       ctlr = (*c)->ctlr;
+       c = (ctlr_info_t *) cmd->device->host->hostdata[0];
+       ctlr = c->ctlr;
 
        rc = lookup_scsi3addr(ctlr, cmd->device->channel, cmd->device->id, 
                        cmd->device->lun, scsi3addr);
@@ -1431,7 +1465,7 @@ cciss_scsi_queue_command (struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd
            see what the device thinks of it. */
 
        spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
-       cp = scsi_cmd_alloc(*c);
+       cp = scsi_cmd_alloc(c);
        spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
        if (cp == NULL) {                       /* trouble... */
                printk("scsi_cmd_alloc returned NULL!\n");
@@ -1489,15 +1523,14 @@ cciss_scsi_queue_command (struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd
                BUG();
                break;
        }
-
-       cciss_scatter_gather((*c)->pdev, cp, cmd); // Fill the SG list
+       cciss_scatter_gather(c, cp, cmd);
 
        /* Put the request on the tail of the request queue */
 
        spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
-       addQ(&(*c)->reqQ, cp);
-       (*c)->Qdepth++;
-       start_io(*c);
+       addQ(&c->reqQ, cp);
+       c->Qdepth++;
+       start_io(c);
        spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
 
        /* the cmd'll come back via intr handler in complete_scsi_command()  */
@@ -1514,7 +1547,7 @@ cciss_unregister_scsi(int ctlr)
        /* we are being forcibly unloaded, and may not refuse. */
 
        spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
-       sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr;
+       sa = hba[ctlr]->scsi_ctlr;
        stk = &sa->cmd_stack; 
 
        /* if we weren't ever actually registered, don't unregister */ 
@@ -1541,7 +1574,7 @@ cciss_engage_scsi(int ctlr)
        unsigned long flags;
 
        spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
-       sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr;
+       sa = hba[ctlr]->scsi_ctlr;
        stk = &sa->cmd_stack; 
 
        if (sa->registered) {
@@ -1654,14 +1687,14 @@ static int cciss_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
        int rc;
        CommandList_struct *cmd_in_trouble;
        unsigned char lunaddr[8];
-       ctlr_info_t **c;
+       ctlr_info_t *c;
        int ctlr;
 
        /* find the controller to which the command to be aborted was sent */
-       c = (ctlr_info_t **) &scsicmd->device->host->hostdata[0];       
+       c = (ctlr_info_t *) scsicmd->device->host->hostdata[0];
        if (c == NULL) /* paranoia */
                return FAILED;
-       ctlr = (*c)->ctlr;
+       ctlr = c->ctlr;
        printk(KERN_WARNING "cciss%d: resetting tape drive or medium changer.\n", ctlr);
        /* find the command that's giving us trouble */
        cmd_in_trouble = (CommandList_struct *) scsicmd->host_scribble;
@@ -1671,7 +1704,7 @@ static int cciss_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
        /* send a reset to the SCSI LUN which the command was sent to */
        rc = sendcmd_withirq(CCISS_RESET_MSG, ctlr, NULL, 0, 0, lunaddr,
                TYPE_MSG);
-       if (rc == 0 && wait_for_device_to_become_ready(*c, lunaddr) == 0)
+       if (rc == 0 && wait_for_device_to_become_ready(c, lunaddr) == 0)
                return SUCCESS;
        printk(KERN_WARNING "cciss%d: resetting device failed.\n", ctlr);
        return FAILED;
@@ -1682,14 +1715,14 @@ static int  cciss_eh_abort_handler(struct scsi_cmnd *scsicmd)
        int rc;
        CommandList_struct *cmd_to_abort;
        unsigned char lunaddr[8];
-       ctlr_info_t **c;
+       ctlr_info_t *c;
        int ctlr;
 
        /* find the controller to which the command to be aborted was sent */
-       c = (ctlr_info_t **) &scsicmd->device->host->hostdata[0];       
+       c = (ctlr_info_t *) scsicmd->device->host->hostdata[0];
        if (c == NULL) /* paranoia */
                return FAILED;
-       ctlr = (*c)->ctlr;
+       ctlr = c->ctlr;
        printk(KERN_WARNING "cciss%d: aborting tardy SCSI cmd\n", ctlr);
 
        /* find the command to be aborted */
index 7b750245ae76b892e4265c6f5ba4af7bbd5731be..6d5822fe851aeaf6759b76ea68fd39c116ea81d7 100644 (file)
 
 #include <scsi/scsicam.h> /* possibly irrelevant, since we don't show disks */
 
-               // the scsi id of the adapter...
+               /* the scsi id of the adapter... */
 #define SELF_SCSI_ID 15
-               // 15 is somewhat arbitrary, since the scsi-2 bus
-               // that's presented by the driver to the OS is
-               // fabricated.  The "real" scsi-3 bus the 
-               // hardware presents is fabricated too.
-               // The actual, honest-to-goodness physical
-               // bus that the devices are attached to is not 
-               // addressible natively, and may in fact turn
-               // out to be not scsi at all.
+               /* 15 is somewhat arbitrary, since the scsi-2 bus
+                  that's presented by the driver to the OS is
+                  fabricated.  The "real" scsi-3 bus the
+                  hardware presents is fabricated too.
+                  The actual, honest-to-goodness physical
+                  bus that the devices are attached to is not
+                  addressible natively, and may in fact turn
+                  out to be not scsi at all. */
 
 #define SCSI_CCISS_CAN_QUEUE 2
 
index 6422651ec364197ed9418f4a3bafb966208a8417..91d11631cec96a523f8f7f9504ce6405edba920a 100644 (file)
@@ -448,11 +448,8 @@ static int __init cpqarray_register_ctlr( int i, struct pci_dev *pdev)
                blk_queue_bounce_limit(q, hba[i]->pci_dev->dma_mask);
 
        /* This is a hardware imposed limit. */
-       blk_queue_max_hw_segments(q, SG_MAX);
+       blk_queue_max_segments(q, SG_MAX);
 
-       /* This is a driver limit and could be eliminated. */
-       blk_queue_max_phys_segments(q, SG_MAX);
-       
        init_timer(&hba[i]->timer);
        hba[i]->timer.expires = jiffies + IDA_TIMER;
        hba[i]->timer.data = (unsigned long)hba[i];
index 1292e062066337d40708d4449c560f9af61bb384..4df3b40b1057d225fe310601c77021a6f37f0d7c 100644 (file)
@@ -709,9 +709,8 @@ void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int max_seg_s) __mu
 
        max_seg_s = min(queue_max_sectors(b) * queue_logical_block_size(b), max_seg_s);
 
-       blk_queue_max_sectors(q, max_seg_s >> 9);
-       blk_queue_max_phys_segments(q, max_segments ? max_segments : MAX_PHYS_SEGMENTS);
-       blk_queue_max_hw_segments(q, max_segments ? max_segments : MAX_HW_SEGMENTS);
+       blk_queue_max_hw_sectors(q, max_seg_s >> 9);
+       blk_queue_max_segments(q, max_segments ? max_segments : BLK_MAX_SEGMENTS);
        blk_queue_max_segment_size(q, max_seg_s);
        blk_queue_logical_block_size(q, 512);
        blk_queue_segment_boundary(q, PAGE_SIZE-1);
index 3266b4f65daa37dec3110ff2220f8d4b7c1bfb42..b9b117059b624973b7d089009f5cb33632d8b02d 100644 (file)
@@ -4234,7 +4234,7 @@ static int __init floppy_init(void)
                err = -ENOMEM;
                goto out_unreg_driver;
        }
-       blk_queue_max_sectors(floppy_queue, 64);
+       blk_queue_max_hw_sectors(floppy_queue, 64);
 
        blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
                            floppy_find, NULL, NULL);
index d5cdce08ffd2765aa1f5b3cc83b399093bbf09e7..5116c65c07cb71e9384372faaf7a7d9fa8c29d89 100644 (file)
@@ -719,7 +719,7 @@ static int __init hd_init(void)
                return -ENOMEM;
        }
 
-       blk_queue_max_sectors(hd_queue, 255);
+       blk_queue_max_hw_sectors(hd_queue, 255);
        init_timer(&device_timer);
        device_timer.function = hd_times_out;
        blk_queue_logical_block_size(hd_queue, 512);
index 02b2583df7fc225184dbf704a28aade8d24128ec..5416c9a606e43694b59dc0dec09075b8257bf964 100644 (file)
@@ -980,7 +980,7 @@ static int mg_probe(struct platform_device *plat_dev)
                                __func__, __LINE__);
                goto probe_err_6;
        }
-       blk_queue_max_sectors(host->breq, MG_MAX_SECTS);
+       blk_queue_max_hw_sectors(host->breq, MG_MAX_SECTS);
        blk_queue_logical_block_size(host->breq, MG_SECTOR_SIZE);
 
        init_timer(&host->timer);
index 569e39e8f1143fd4c896344fa25e3e653f8e6a89..e712cd51af1543c75ca13092c1662e551df256f4 100644 (file)
@@ -906,7 +906,7 @@ static int __init pd_init(void)
        if (!pd_queue)
                goto out1;
 
-       blk_queue_max_sectors(pd_queue, cluster);
+       blk_queue_max_hw_sectors(pd_queue, cluster);
 
        if (register_blkdev(major, name))
                goto out2;
index ea54ea393553831c6ba4a2066e9cb63859cd4e5b..ddb4f9abd480b8f0cb6ce013d6c514e5a211d120 100644 (file)
@@ -956,8 +956,7 @@ static int __init pf_init(void)
                return -ENOMEM;
        }
 
-       blk_queue_max_phys_segments(pf_queue, cluster);
-       blk_queue_max_hw_segments(pf_queue, cluster);
+       blk_queue_max_segments(pf_queue, cluster);
 
        for (pf = units, unit = 0; unit < PF_UNITS; pf++, unit++) {
                struct gendisk *disk = pf->disk;
index 68b5957f107cd4c5e675576457c103330458de11..b72935b8f2036e3ea954b5560fe88fd3875f5d96 100644 (file)
@@ -569,6 +569,7 @@ static struct packet_data *pkt_alloc_packet_data(int frames)
        }
 
        spin_lock_init(&pkt->lock);
+       bio_list_init(&pkt->orig_bios);
 
        for (i = 0; i < frames; i++) {
                struct bio *bio = pkt_bio_alloc(1);
@@ -720,43 +721,6 @@ static void pkt_rbtree_insert(struct pktcdvd_device *pd, struct pkt_rb_node *nod
        pd->bio_queue_size++;
 }
 
-/*
- * Add a bio to a single linked list defined by its head and tail pointers.
- */
-static void pkt_add_list_last(struct bio *bio, struct bio **list_head, struct bio **list_tail)
-{
-       bio->bi_next = NULL;
-       if (*list_tail) {
-               BUG_ON((*list_head) == NULL);
-               (*list_tail)->bi_next = bio;
-               (*list_tail) = bio;
-       } else {
-               BUG_ON((*list_head) != NULL);
-               (*list_head) = bio;
-               (*list_tail) = bio;
-       }
-}
-
-/*
- * Remove and return the first bio from a single linked list defined by its
- * head and tail pointers.
- */
-static inline struct bio *pkt_get_list_first(struct bio **list_head, struct bio **list_tail)
-{
-       struct bio *bio;
-
-       if (*list_head == NULL)
-               return NULL;
-
-       bio = *list_head;
-       *list_head = bio->bi_next;
-       if (*list_head == NULL)
-               *list_tail = NULL;
-
-       bio->bi_next = NULL;
-       return bio;
-}
-
 /*
  * Send a packet_command to the underlying block device and
  * wait for completion.
@@ -876,13 +840,10 @@ static noinline_for_stack int pkt_set_speed(struct pktcdvd_device *pd,
 static void pkt_queue_bio(struct pktcdvd_device *pd, struct bio *bio)
 {
        spin_lock(&pd->iosched.lock);
-       if (bio_data_dir(bio) == READ) {
-               pkt_add_list_last(bio, &pd->iosched.read_queue,
-                                 &pd->iosched.read_queue_tail);
-       } else {
-               pkt_add_list_last(bio, &pd->iosched.write_queue,
-                                 &pd->iosched.write_queue_tail);
-       }
+       if (bio_data_dir(bio) == READ)
+               bio_list_add(&pd->iosched.read_queue, bio);
+       else
+               bio_list_add(&pd->iosched.write_queue, bio);
        spin_unlock(&pd->iosched.lock);
 
        atomic_set(&pd->iosched.attention, 1);
@@ -917,8 +878,8 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd)
                int reads_queued, writes_queued;
 
                spin_lock(&pd->iosched.lock);
-               reads_queued = (pd->iosched.read_queue != NULL);
-               writes_queued = (pd->iosched.write_queue != NULL);
+               reads_queued = !bio_list_empty(&pd->iosched.read_queue);
+               writes_queued = !bio_list_empty(&pd->iosched.write_queue);
                spin_unlock(&pd->iosched.lock);
 
                if (!reads_queued && !writes_queued)
@@ -927,7 +888,7 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd)
                if (pd->iosched.writing) {
                        int need_write_seek = 1;
                        spin_lock(&pd->iosched.lock);
-                       bio = pd->iosched.write_queue;
+                       bio = bio_list_peek(&pd->iosched.write_queue);
                        spin_unlock(&pd->iosched.lock);
                        if (bio && (bio->bi_sector == pd->iosched.last_write))
                                need_write_seek = 0;
@@ -950,13 +911,10 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd)
                }
 
                spin_lock(&pd->iosched.lock);
-               if (pd->iosched.writing) {
-                       bio = pkt_get_list_first(&pd->iosched.write_queue,
-                                                &pd->iosched.write_queue_tail);
-               } else {
-                       bio = pkt_get_list_first(&pd->iosched.read_queue,
-                                                &pd->iosched.read_queue_tail);
-               }
+               if (pd->iosched.writing)
+                       bio = bio_list_pop(&pd->iosched.write_queue);
+               else
+                       bio = bio_list_pop(&pd->iosched.read_queue);
                spin_unlock(&pd->iosched.lock);
 
                if (!bio)
@@ -992,14 +950,14 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd)
 static int pkt_set_segment_merging(struct pktcdvd_device *pd, struct request_queue *q)
 {
        if ((pd->settings.size << 9) / CD_FRAMESIZE
-           <= queue_max_phys_segments(q)) {
+           <= queue_max_segments(q)) {
                /*
                 * The cdrom device can handle one segment/frame
                 */
                clear_bit(PACKET_MERGE_SEGS, &pd->flags);
                return 0;
        } else if ((pd->settings.size << 9) / PAGE_SIZE
-                  <= queue_max_phys_segments(q)) {
+                  <= queue_max_segments(q)) {
                /*
                 * We can handle this case at the expense of some extra memory
                 * copies during write operations
@@ -1114,7 +1072,7 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt)
        int f;
        char written[PACKET_MAX_SIZE];
 
-       BUG_ON(!pkt->orig_bios);
+       BUG_ON(bio_list_empty(&pkt->orig_bios));
 
        atomic_set(&pkt->io_wait, 0);
        atomic_set(&pkt->io_errors, 0);
@@ -1124,7 +1082,7 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt)
         */
        memset(written, 0, sizeof(written));
        spin_lock(&pkt->lock);
-       for (bio = pkt->orig_bios; bio; bio = bio->bi_next) {
+       bio_list_for_each(bio, &pkt->orig_bios) {
                int first_frame = (bio->bi_sector - pkt->sector) / (CD_FRAMESIZE >> 9);
                int num_frames = bio->bi_size / CD_FRAMESIZE;
                pd->stats.secs_w += num_frames * (CD_FRAMESIZE >> 9);
@@ -1363,7 +1321,7 @@ try_next_bio:
                        break;
                pkt_rbtree_erase(pd, node);
                spin_lock(&pkt->lock);
-               pkt_add_list_last(bio, &pkt->orig_bios, &pkt->orig_bios_tail);
+               bio_list_add(&pkt->orig_bios, bio);
                pkt->write_size += bio->bi_size / CD_FRAMESIZE;
                spin_unlock(&pkt->lock);
        }
@@ -1409,7 +1367,7 @@ static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt)
         */
        frames_write = 0;
        spin_lock(&pkt->lock);
-       for (bio = pkt->orig_bios; bio; bio = bio->bi_next) {
+       bio_list_for_each(bio, &pkt->orig_bios) {
                int segment = bio->bi_idx;
                int src_offs = 0;
                int first_frame = (bio->bi_sector - pkt->sector) / (CD_FRAMESIZE >> 9);
@@ -1472,20 +1430,14 @@ static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt)
 
 static void pkt_finish_packet(struct packet_data *pkt, int uptodate)
 {
-       struct bio *bio, *next;
+       struct bio *bio;
 
        if (!uptodate)
                pkt->cache_valid = 0;
 
        /* Finish all bios corresponding to this packet */
-       bio = pkt->orig_bios;
-       while (bio) {
-               next = bio->bi_next;
-               bio->bi_next = NULL;
+       while ((bio = bio_list_pop(&pkt->orig_bios)))
                bio_endio(bio, uptodate ? 0 : -EIO);
-               bio = next;
-       }
-       pkt->orig_bios = pkt->orig_bios_tail = NULL;
 }
 
 static void pkt_run_state_machine(struct pktcdvd_device *pd, struct packet_data *pkt)
@@ -2360,7 +2312,7 @@ static int pkt_open_dev(struct pktcdvd_device *pd, fmode_t write)
                 * even if the size is a multiple of the packet size.
                 */
                spin_lock_irq(q->queue_lock);
-               blk_queue_max_sectors(q, pd->settings.size);
+               blk_queue_max_hw_sectors(q, pd->settings.size);
                spin_unlock_irq(q->queue_lock);
                set_bit(PACKET_WRITABLE, &pd->flags);
        } else {
@@ -2567,8 +2519,7 @@ static int pkt_make_request(struct request_queue *q, struct bio *bio)
                        spin_lock(&pkt->lock);
                        if ((pkt->state == PACKET_WAITING_STATE) ||
                            (pkt->state == PACKET_READ_WAIT_STATE)) {
-                               pkt_add_list_last(bio, &pkt->orig_bios,
-                                                 &pkt->orig_bios_tail);
+                               bio_list_add(&pkt->orig_bios, bio);
                                pkt->write_size += bio->bi_size / CD_FRAMESIZE;
                                if ((pkt->write_size >= pkt->frames) &&
                                    (pkt->state == PACKET_WAITING_STATE)) {
@@ -2662,7 +2613,7 @@ static void pkt_init_queue(struct pktcdvd_device *pd)
 
        blk_queue_make_request(q, pkt_make_request);
        blk_queue_logical_block_size(q, CD_FRAMESIZE);
-       blk_queue_max_sectors(q, PACKET_MAX_SECTORS);
+       blk_queue_max_hw_sectors(q, PACKET_MAX_SECTORS);
        blk_queue_merge_bvec(q, pkt_merge_bvec);
        q->queuedata = pd;
 }
@@ -2898,6 +2849,8 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
 
        spin_lock_init(&pd->lock);
        spin_lock_init(&pd->iosched.lock);
+       bio_list_init(&pd->iosched.read_queue);
+       bio_list_init(&pd->iosched.write_queue);
        sprintf(pd->name, DRIVER_NAME"%d", idx);
        init_waitqueue_head(&pd->wqueue);
        pd->bio_queue = RB_ROOT;
index 03a130dca8ab541ad81bbb7db2095da6a5a26551..bc95469d33c122018e96ccbc9576370e64c89afd 100644 (file)
@@ -474,7 +474,7 @@ static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev)
 
        blk_queue_bounce_limit(queue, BLK_BOUNCE_HIGH);
 
-       blk_queue_max_sectors(queue, dev->bounce_size >> 9);
+       blk_queue_max_hw_sectors(queue, dev->bounce_size >> 9);
        blk_queue_segment_boundary(queue, -1UL);
        blk_queue_dma_alignment(queue, dev->blk_size-1);
        blk_queue_logical_block_size(queue, dev->blk_size);
@@ -482,8 +482,7 @@ static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev)
        blk_queue_ordered(queue, QUEUE_ORDERED_DRAIN_FLUSH,
                          ps3disk_prepare_flush);
 
-       blk_queue_max_phys_segments(queue, -1);
-       blk_queue_max_hw_segments(queue, -1);
+       blk_queue_max_segments(queue, -1);
        blk_queue_max_segment_size(queue, dev->bounce_size);
 
        gendisk = alloc_disk(PS3DISK_MINORS);
index 1fb6c3135fc8db04f278dc0d45809fc0ad10181d..e4460822997293c324e3a5d617ec49acd0801ccd 100644 (file)
@@ -751,10 +751,9 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
        priv->queue = queue;
        queue->queuedata = dev;
        blk_queue_make_request(queue, ps3vram_make_request);
-       blk_queue_max_phys_segments(queue, MAX_PHYS_SEGMENTS);
-       blk_queue_max_hw_segments(queue, MAX_HW_SEGMENTS);
-       blk_queue_max_segment_size(queue, MAX_SEGMENT_SIZE);
-       blk_queue_max_sectors(queue, SAFE_MAX_SECTORS);
+       blk_queue_max_segments(queue, BLK_MAX_SEGMENTS);
+       blk_queue_max_segment_size(queue, BLK_MAX_SEGMENT_SIZE);
+       blk_queue_max_hw_sectors(queue, BLK_SAFE_MAX_SECTORS);
 
        gendisk = alloc_disk(1);
        if (!gendisk) {
index 411f064760b41db69a4ffae999b92f24b89fba3b..48e8fee9f2d4f8aa6bacf4243694a430b53fdae9 100644 (file)
@@ -691,9 +691,8 @@ static int probe_disk(struct vdc_port *port)
 
        port->disk = g;
 
-       blk_queue_max_hw_segments(q, port->ring_cookies);
-       blk_queue_max_phys_segments(q, port->ring_cookies);
-       blk_queue_max_sectors(q, port->max_xfer_size);
+       blk_queue_max_segments(q, port->ring_cookies);
+       blk_queue_max_hw_sectors(q, port->max_xfer_size);
        g->major = vdc_major;
        g->first_minor = port->vio.vdev->dev_no << PARTITION_SHIFT;
        strcpy(g->disk_name, port->disk_name);
index a7c4184f4a63355539976a010e0c50700d4c5318..b70f0fca9a42e724e3911d62cd64729a2f20ce4b 100644 (file)
@@ -409,7 +409,7 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 static void carm_remove_one (struct pci_dev *pdev);
 static int carm_bdev_getgeo(struct block_device *bdev, struct hd_geometry *geo);
 
-static struct pci_device_id carm_pci_tbl[] = {
+static const struct pci_device_id carm_pci_tbl[] = {
        { PCI_VENDOR_ID_PROMISE, 0x8000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
        { PCI_VENDOR_ID_PROMISE, 0x8002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
        { }     /* terminate list */
@@ -1518,8 +1518,7 @@ static int carm_init_disks(struct carm_host *host)
                        break;
                }
                disk->queue = q;
-               blk_queue_max_hw_segments(q, CARM_MAX_REQ_SG);
-               blk_queue_max_phys_segments(q, CARM_MAX_REQ_SG);
+               blk_queue_max_segments(q, CARM_MAX_REQ_SG);
                blk_queue_segment_boundary(q, CARM_SG_BOUNDARY);
 
                q->queuedata = port;
index c739b203fe91321b955905b72c3eab3e93f8d821..2e889838e819016c8c693cba1d0498595a027565 100644 (file)
@@ -393,7 +393,7 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum);
 #define ub_usb_ids  usb_storage_usb_ids
 #else
 
-static struct usb_device_id ub_usb_ids[] = {
+static const struct usb_device_id ub_usb_ids[] = {
        { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_BULK) },
        { }
 };
@@ -2320,10 +2320,9 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum)
        disk->queue = q;
 
        blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH);
-       blk_queue_max_hw_segments(q, UB_MAX_REQ_SG);
-       blk_queue_max_phys_segments(q, UB_MAX_REQ_SG);
+       blk_queue_max_segments(q, UB_MAX_REQ_SG);
        blk_queue_segment_boundary(q, 0xffffffff);      /* Dubious. */
-       blk_queue_max_sectors(q, UB_MAX_SECTORS);
+       blk_queue_max_hw_sectors(q, UB_MAX_SECTORS);
        blk_queue_logical_block_size(q, lun->capacity.bsize);
 
        lun->disk = disk;
index 1b3def1e8591d330bc3aa9b4730086b7fc6844c4..788d93882ab961dc8cc71530e710f5ab33412aad 100644 (file)
@@ -462,9 +462,8 @@ retry:
        }
 
        d->disk = g;
-       blk_queue_max_hw_segments(q, VIOMAXBLOCKDMA);
-       blk_queue_max_phys_segments(q, VIOMAXBLOCKDMA);
-       blk_queue_max_sectors(q, VIODASD_MAXSECTORS);
+       blk_queue_max_segments(q, VIOMAXBLOCKDMA);
+       blk_queue_max_hw_sectors(q, VIODASD_MAXSECTORS);
        g->major = VIODASD_MAJOR;
        g->first_minor = dev_no << PARTITION_SHIFT;
        if (dev_no >= 26)
index 7eff828b21170731fd5c02290136a12665b4e9ea..3c64af05fa82a0fa79dbf26c9cf84c509b54c604 100644 (file)
@@ -435,7 +435,7 @@ static void __devexit virtblk_remove(struct virtio_device *vdev)
        kfree(vblk);
 }
 
-static struct virtio_device_id id_table[] = {
+static const struct virtio_device_id id_table[] = {
        { VIRTIO_ID_BLOCK, VIRTIO_DEV_ANY_ID },
        { 0 },
 };
index d1fd032e751494cb7f452c470383f14d45ab3ec7..1a325fb05c9282745013d53e541e13b7b748d1a8 100644 (file)
@@ -242,7 +242,7 @@ static int __init xd_init(void)
        }
 
        /* xd_maxsectors depends on controller - so set after detection */
-       blk_queue_max_sectors(xd_queue, xd_maxsectors);
+       blk_queue_max_hw_sectors(xd_queue, xd_maxsectors);
 
        for (i = 0; i < xd_drives; i++)
                add_disk(xd_gendisk[i]);
index 05a31e55d27817bed3f8157c91389c31f0adb1f8..9c09694b2520cc5a2422416431576a46d0871eaf 100644 (file)
@@ -346,15 +346,14 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
 
        /* Hard sector size and max sectors impersonate the equiv. hardware. */
        blk_queue_logical_block_size(rq, sector_size);
-       blk_queue_max_sectors(rq, 512);
+       blk_queue_max_hw_sectors(rq, 512);
 
        /* Each segment in a request is up to an aligned page in size. */
        blk_queue_segment_boundary(rq, PAGE_SIZE - 1);
        blk_queue_max_segment_size(rq, PAGE_SIZE);
 
        /* Ensure a merged request will fit in a single I/O ring slot. */
-       blk_queue_max_phys_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
-       blk_queue_max_hw_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+       blk_queue_max_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
 
        /* Make sure buffer addresses are sector-aligned. */
        blk_queue_dma_alignment(rq, 511);
@@ -1050,7 +1049,7 @@ static const struct block_device_operations xlvbd_block_fops =
 };
 
 
-static struct xenbus_device_id blkfront_ids[] = {
+static const struct xenbus_device_id blkfront_ids[] = {
        { "vbd" },
        { "" }
 };
index e5c5415eb45eb7a7e8f350427be29fcfe2fb3eec..e1c95e208a6656c50a8e44b04bab25fc4a65d7cf 100644 (file)
@@ -1227,7 +1227,7 @@ static int __devexit ace_of_remove(struct of_device *op)
 }
 
 /* Match table for of_platform binding */
-static struct of_device_id ace_of_match[] __devinitdata = {
+static const struct of_device_id ace_of_match[] __devinitconst = {
        { .compatible = "xlnx,opb-sysace-1.00.b", },
        { .compatible = "xlnx,opb-sysace-1.00.c", },
        { .compatible = "xlnx,xps-sysace-1.00.a", },
index e789e6c9a42217681e9a0a698181e1f1dc971455..03c71f7698cb64ffd2aa1de3f31fc600648ce675 100644 (file)
@@ -741,7 +741,7 @@ static int __devinit probe_gdrom_setupqueue(void)
 {
        blk_queue_logical_block_size(gd.gdrom_rq, GDROM_HARD_SECTOR);
        /* using DMA so memory will need to be contiguous */
-       blk_queue_max_hw_segments(gd.gdrom_rq, 1);
+       blk_queue_max_segments(gd.gdrom_rq, 1);
        /* set a large max size to get most from DMA */
        blk_queue_max_segment_size(gd.gdrom_rq, 0x40000);
        gd.disk->queue = gd.gdrom_rq;
index 57ca69e0ac553a086ec1751441188c6415f4fe56..cc435be0bc136840153e91bbb0ef4cbae0bf54d9 100644 (file)
@@ -616,9 +616,8 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        gendisk->first_minor = deviceno;
        strncpy(gendisk->disk_name, c->name,
                        sizeof(gendisk->disk_name));
-       blk_queue_max_hw_segments(q, 1);
-       blk_queue_max_phys_segments(q, 1);
-       blk_queue_max_sectors(q, 4096 / 512);
+       blk_queue_max_segments(q, 1);
+       blk_queue_max_hw_sectors(q, 4096 / 512);
        gendisk->queue = q;
        gendisk->fops = &viocd_fops;
        gendisk->flags = GENHD_FL_CD|GENHD_FL_REMOVABLE;
index f706b1dffdb31f082144f419fb5d28d6d8ccbbfc..ada25bb8941e5c0fa28ff068f66b0e14be700c55 100644 (file)
@@ -1185,11 +1185,6 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
 
        rep = (down == 2);
 
-#ifdef CONFIG_MAC_EMUMOUSEBTN
-       if (mac_hid_mouse_emulate_buttons(1, keycode, down))
-               return;
-#endif /* CONFIG_MAC_EMUMOUSEBTN */
-
        if ((raw_mode = (kbd->kbdmode == VC_RAW)) && !hw_raw)
                if (emulate_raw(vc, keycode, !down << 7))
                        if (keycode < BTN_MISC && printk_ratelimit())
@@ -1328,6 +1323,21 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type,
        schedule_console_callback();
 }
 
+static bool kbd_match(struct input_handler *handler, struct input_dev *dev)
+{
+       int i;
+
+       if (test_bit(EV_SND, dev->evbit))
+               return true;
+
+       if (test_bit(EV_KEY, dev->evbit))
+               for (i = KEY_RESERVED; i < BTN_MISC; i++)
+                       if (test_bit(i, dev->keybit))
+                               return true;
+
+       return false;
+}
+
 /*
  * When a keyboard (or other input device) is found, the kbd_connect
  * function is called. The function then looks at the device, and if it
@@ -1339,14 +1349,6 @@ static int kbd_connect(struct input_handler *handler, struct input_dev *dev,
 {
        struct input_handle *handle;
        int error;
-       int i;
-
-       for (i = KEY_RESERVED; i < BTN_MISC; i++)
-               if (test_bit(i, dev->keybit))
-                       break;
-
-       if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit))
-               return -ENODEV;
 
        handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
        if (!handle)
@@ -1412,6 +1414,7 @@ MODULE_DEVICE_TABLE(input, kbd_ids);
 
 static struct input_handler kbd_handler = {
        .event          = kbd_event,
+       .match          = kbd_match,
        .connect        = kbd_connect,
        .disconnect     = kbd_disconnect,
        .start          = kbd_start,
index fdbcc9fd6d3143a00810fd664d77379ee083717b..5eb83c3ca20de35be340031015a93495ae19e12b 100644 (file)
@@ -336,14 +336,12 @@ static int nvram_ioctl(struct inode *inode, struct file *file,
 
 static int nvram_open(struct inode *inode, struct file *file)
 {
-       lock_kernel();
        spin_lock(&nvram_state_lock);
 
        if ((nvram_open_cnt && (file->f_flags & O_EXCL)) ||
            (nvram_open_mode & NVRAM_EXCL) ||
            ((file->f_mode & FMODE_WRITE) && (nvram_open_mode & NVRAM_WRITE))) {
                spin_unlock(&nvram_state_lock);
-               unlock_kernel();
                return -EBUSY;
        }
 
@@ -354,7 +352,6 @@ static int nvram_open(struct inode *inode, struct file *file)
        nvram_open_cnt++;
 
        spin_unlock(&nvram_state_lock);
-       unlock_kernel();
 
        return 0;
 }
index 6fe4f7701188c87423fb3fb85987f76cd95a5f41..578595c4425d2836cdf283eb44e0e1039e060fa5 100644 (file)
@@ -40,7 +40,6 @@ struct sh_cmt_priv {
        struct platform_device *pdev;
 
        unsigned long flags;
-       unsigned long flags_suspend;
        unsigned long match_value;
        unsigned long next_match_value;
        unsigned long max_match_value;
@@ -432,6 +431,11 @@ static void sh_cmt_clocksource_disable(struct clocksource *cs)
        sh_cmt_stop(cs_to_sh_cmt(cs), FLAG_CLOCKSOURCE);
 }
 
+static void sh_cmt_clocksource_resume(struct clocksource *cs)
+{
+       sh_cmt_start(cs_to_sh_cmt(cs), FLAG_CLOCKSOURCE);
+}
+
 static int sh_cmt_register_clocksource(struct sh_cmt_priv *p,
                                       char *name, unsigned long rating)
 {
@@ -442,6 +446,8 @@ static int sh_cmt_register_clocksource(struct sh_cmt_priv *p,
        cs->read = sh_cmt_clocksource_read;
        cs->enable = sh_cmt_clocksource_enable;
        cs->disable = sh_cmt_clocksource_disable;
+       cs->suspend = sh_cmt_clocksource_disable;
+       cs->resume = sh_cmt_clocksource_resume;
        cs->mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
        cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
        pr_info("sh_cmt: %s used as clock source\n", cs->name);
@@ -674,38 +680,11 @@ static int __devexit sh_cmt_remove(struct platform_device *pdev)
        return -EBUSY; /* cannot unregister clockevent and clocksource */
 }
 
-static int sh_cmt_suspend(struct device *dev)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-       struct sh_cmt_priv *p = platform_get_drvdata(pdev);
-
-       /* save flag state and stop CMT channel */
-       p->flags_suspend = p->flags;
-       sh_cmt_stop(p, p->flags);
-       return 0;
-}
-
-static int sh_cmt_resume(struct device *dev)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-       struct sh_cmt_priv *p = platform_get_drvdata(pdev);
-
-       /* start CMT channel from saved state */
-       sh_cmt_start(p, p->flags_suspend);
-       return 0;
-}
-
-static struct dev_pm_ops sh_cmt_dev_pm_ops = {
-       .suspend = sh_cmt_suspend,
-       .resume = sh_cmt_resume,
-};
-
 static struct platform_driver sh_cmt_device_driver = {
        .probe          = sh_cmt_probe,
        .remove         = __devexit_p(sh_cmt_remove),
        .driver         = {
                .name   = "sh_cmt",
-               .pm     = &sh_cmt_dev_pm_ops,
        }
 };
 
index d485cdd8cbacf0a16410e50fb2b195c0107537f2..70fef40cd22f0f0d0d9c46add51943a51e6cea52 100644 (file)
@@ -1571,7 +1571,7 @@ static int sbp2_scsi_slave_configure(struct scsi_device *sdev)
                sdev->start_stop_pwr_cond = 1;
 
        if (lu->tgt->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS)
-               blk_queue_max_sectors(sdev->request_queue, 128 * 1024 / 512);
+               blk_queue_max_hw_sectors(sdev->request_queue, 128 * 1024 / 512);
 
        blk_queue_max_segment_size(sdev->request_queue, SBP2_MAX_SEG_SIZE);
 
index 5d1c2603a130f84e8506535a79108ee8691f36d7..2b0bd0b042d6df7bd8513f20232619853c130939 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/i2c-pnx.h>
 #include <linux/io.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
 #include <mach/hardware.h>
 #include <mach/i2c.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
 
 #define I2C_PNX_TIMEOUT                10 /* msec */
 #define I2C_PNX_SPEED_KHZ      100
 #define I2C_PNX_REGION_SIZE    0x100
-#define PNX_DEFAULT_FREQ       13 /* MHz */
 
 static inline int wait_timeout(long timeout, struct i2c_pnx_algo_data *data)
 {
@@ -50,22 +50,21 @@ static inline int wait_reset(long timeout, struct i2c_pnx_algo_data *data)
        return (timeout <= 0);
 }
 
-static inline void i2c_pnx_arm_timer(struct i2c_adapter *adap)
+static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data)
 {
-       struct i2c_pnx_algo_data *data = adap->algo_data;
-       struct timer_list *timer = &data->mif.timer;
-       int expires = I2C_PNX_TIMEOUT / (1000 / HZ);
+       struct timer_list *timer = &alg_data->mif.timer;
+       unsigned long expires = msecs_to_jiffies(I2C_PNX_TIMEOUT);
 
        if (expires <= 1)
                expires = 2;
 
        del_timer_sync(timer);
 
-       dev_dbg(&adap->dev, "Timer armed at %lu plus %u jiffies.\n",
+       dev_dbg(&alg_data->adapter.dev, "Timer armed at %lu plus %lu jiffies.\n",
                jiffies, expires);
 
        timer->expires = jiffies + expires;
-       timer->data = (unsigned long)adap;
+       timer->data = (unsigned long)&alg_data;
 
        add_timer(timer);
 }
@@ -77,34 +76,34 @@ static inline void i2c_pnx_arm_timer(struct i2c_adapter *adap)
  *
  * Generate a START signal in the desired mode.
  */
-static int i2c_pnx_start(unsigned char slave_addr, struct i2c_adapter *adap)
+static int i2c_pnx_start(unsigned char slave_addr,
+       struct i2c_pnx_algo_data *alg_data)
 {
-       struct i2c_pnx_algo_data *alg_data = adap->algo_data;
-
-       dev_dbg(&adap->dev, "%s(): addr 0x%x mode %d\n", __func__,
+       dev_dbg(&alg_data->adapter.dev, "%s(): addr 0x%x mode %d\n", __func__,
                slave_addr, alg_data->mif.mode);
 
        /* Check for 7 bit slave addresses only */
        if (slave_addr & ~0x7f) {
-               dev_err(&adap->dev, "%s: Invalid slave address %x. "
-                      "Only 7-bit addresses are supported\n",
-                      adap->name, slave_addr);
+               dev_err(&alg_data->adapter.dev,
+                       "%s: Invalid slave address %x. Only 7-bit addresses are supported\n",
+                       alg_data->adapter.name, slave_addr);
                return -EINVAL;
        }
 
        /* First, make sure bus is idle */
        if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) {
                /* Somebody else is monopolizing the bus */
-               dev_err(&adap->dev, "%s: Bus busy. Slave addr = %02x, "
-                      "cntrl = %x, stat = %x\n",
-                      adap->name, slave_addr,
-                      ioread32(I2C_REG_CTL(alg_data)),
-                      ioread32(I2C_REG_STS(alg_data)));
+               dev_err(&alg_data->adapter.dev,
+                       "%s: Bus busy. Slave addr = %02x, cntrl = %x, stat = %x\n",
+                       alg_data->adapter.name, slave_addr,
+                       ioread32(I2C_REG_CTL(alg_data)),
+                       ioread32(I2C_REG_STS(alg_data)));
                return -EBUSY;
        } else if (ioread32(I2C_REG_STS(alg_data)) & mstatus_afi) {
                /* Sorry, we lost the bus */
-               dev_err(&adap->dev, "%s: Arbitration failure. "
-                      "Slave addr = %02x\n", adap->name, slave_addr);
+               dev_err(&alg_data->adapter.dev,
+                       "%s: Arbitration failure. Slave addr = %02x\n",
+                       alg_data->adapter.name, slave_addr);
                return -EIO;
        }
 
@@ -115,14 +114,14 @@ static int i2c_pnx_start(unsigned char slave_addr, struct i2c_adapter *adap)
        iowrite32(ioread32(I2C_REG_STS(alg_data)) | mstatus_tdi | mstatus_afi,
                  I2C_REG_STS(alg_data));
 
-       dev_dbg(&adap->dev, "%s(): sending %#x\n", __func__,
+       dev_dbg(&alg_data->adapter.dev, "%s(): sending %#x\n", __func__,
                (slave_addr << 1) | start_bit | alg_data->mif.mode);
 
        /* Write the slave address, START bit and R/W bit */
        iowrite32((slave_addr << 1) | start_bit | alg_data->mif.mode,
                  I2C_REG_TX(alg_data));
 
-       dev_dbg(&adap->dev, "%s(): exit\n", __func__);
+       dev_dbg(&alg_data->adapter.dev, "%s(): exit\n", __func__);
 
        return 0;
 }
@@ -133,13 +132,12 @@ static int i2c_pnx_start(unsigned char slave_addr, struct i2c_adapter *adap)
  *
  * Generate a STOP signal to terminate the master transaction.
  */
-static void i2c_pnx_stop(struct i2c_adapter *adap)
+static void i2c_pnx_stop(struct i2c_pnx_algo_data *alg_data)
 {
-       struct i2c_pnx_algo_data *alg_data = adap->algo_data;
        /* Only 1 msec max timeout due to interrupt context */
        long timeout = 1000;
 
-       dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n",
+       dev_dbg(&alg_data->adapter.dev, "%s(): entering: stat = %04x.\n",
                __func__, ioread32(I2C_REG_STS(alg_data)));
 
        /* Write a STOP bit to TX FIFO */
@@ -153,7 +151,7 @@ static void i2c_pnx_stop(struct i2c_adapter *adap)
                timeout--;
        }
 
-       dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n",
+       dev_dbg(&alg_data->adapter.dev, "%s(): exiting: stat = %04x.\n",
                __func__, ioread32(I2C_REG_STS(alg_data)));
 }
 
@@ -163,12 +161,11 @@ static void i2c_pnx_stop(struct i2c_adapter *adap)
  *
  * Sends one byte of data to the slave
  */
-static int i2c_pnx_master_xmit(struct i2c_adapter *adap)
+static int i2c_pnx_master_xmit(struct i2c_pnx_algo_data *alg_data)
 {
-       struct i2c_pnx_algo_data *alg_data = adap->algo_data;
        u32 val;
 
-       dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n",
+       dev_dbg(&alg_data->adapter.dev, "%s(): entering: stat = %04x.\n",
                __func__, ioread32(I2C_REG_STS(alg_data)));
 
        if (alg_data->mif.len > 0) {
@@ -184,15 +181,15 @@ static int i2c_pnx_master_xmit(struct i2c_adapter *adap)
                alg_data->mif.len--;
                iowrite32(val, I2C_REG_TX(alg_data));
 
-               dev_dbg(&adap->dev, "%s(): xmit %#x [%d]\n", __func__,
-                       val, alg_data->mif.len + 1);
+               dev_dbg(&alg_data->adapter.dev, "%s(): xmit %#x [%d]\n",
+                       __func__, val, alg_data->mif.len + 1);
 
                if (alg_data->mif.len == 0) {
                        if (alg_data->last) {
                                /* Wait until the STOP is seen. */
                                if (wait_timeout(I2C_PNX_TIMEOUT, alg_data))
-                                       dev_err(&adap->dev, "The bus is still "
-                                               "active after timeout\n");
+                                       dev_err(&alg_data->adapter.dev,
+                                               "The bus is still active after timeout\n");
                        }
                        /* Disable master interrupts */
                        iowrite32(ioread32(I2C_REG_CTL(alg_data)) &
@@ -201,14 +198,15 @@ static int i2c_pnx_master_xmit(struct i2c_adapter *adap)
 
                        del_timer_sync(&alg_data->mif.timer);
 
-                       dev_dbg(&adap->dev, "%s(): Waking up xfer routine.\n",
+                       dev_dbg(&alg_data->adapter.dev,
+                               "%s(): Waking up xfer routine.\n",
                                __func__);
 
                        complete(&alg_data->mif.complete);
                }
        } else if (alg_data->mif.len == 0) {
                /* zero-sized transfer */
-               i2c_pnx_stop(adap);
+               i2c_pnx_stop(alg_data);
 
                /* Disable master interrupts. */
                iowrite32(ioread32(I2C_REG_CTL(alg_data)) &
@@ -217,13 +215,14 @@ static int i2c_pnx_master_xmit(struct i2c_adapter *adap)
 
                /* Stop timer. */
                del_timer_sync(&alg_data->mif.timer);
-               dev_dbg(&adap->dev, "%s(): Waking up xfer routine after "
-                       "zero-xfer.\n", __func__);
+               dev_dbg(&alg_data->adapter.dev,
+                       "%s(): Waking up xfer routine after zero-xfer.\n",
+                       __func__);
 
                complete(&alg_data->mif.complete);
        }
 
-       dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n",
+       dev_dbg(&alg_data->adapter.dev, "%s(): exiting: stat = %04x.\n",
                __func__, ioread32(I2C_REG_STS(alg_data)));
 
        return 0;
@@ -235,21 +234,21 @@ static int i2c_pnx_master_xmit(struct i2c_adapter *adap)
  *
  * Reads one byte data from the slave
  */
-static int i2c_pnx_master_rcv(struct i2c_adapter *adap)
+static int i2c_pnx_master_rcv(struct i2c_pnx_algo_data *alg_data)
 {
-       struct i2c_pnx_algo_data *alg_data = adap->algo_data;
        unsigned int val = 0;
        u32 ctl = 0;
 
-       dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n",
+       dev_dbg(&alg_data->adapter.dev, "%s(): entering: stat = %04x.\n",
                __func__, ioread32(I2C_REG_STS(alg_data)));
 
        /* Check, whether there is already data,
         * or we didn't 'ask' for it yet.
         */
        if (ioread32(I2C_REG_STS(alg_data)) & mstatus_rfe) {
-               dev_dbg(&adap->dev, "%s(): Write dummy data to fill "
-                       "Rx-fifo...\n", __func__);
+               dev_dbg(&alg_data->adapter.dev,
+                       "%s(): Write dummy data to fill Rx-fifo...\n",
+                       __func__);
 
                if (alg_data->mif.len == 1) {
                        /* Last byte, do not acknowledge next rcv. */
@@ -281,16 +280,16 @@ static int i2c_pnx_master_rcv(struct i2c_adapter *adap)
        if (alg_data->mif.len > 0) {
                val = ioread32(I2C_REG_RX(alg_data));
                *alg_data->mif.buf++ = (u8) (val & 0xff);
-               dev_dbg(&adap->dev, "%s(): rcv 0x%x [%d]\n", __func__, val,
-                       alg_data->mif.len);
+               dev_dbg(&alg_data->adapter.dev, "%s(): rcv 0x%x [%d]\n",
+                       __func__, val, alg_data->mif.len);
 
                alg_data->mif.len--;
                if (alg_data->mif.len == 0) {
                        if (alg_data->last)
                                /* Wait until the STOP is seen. */
                                if (wait_timeout(I2C_PNX_TIMEOUT, alg_data))
-                                       dev_err(&adap->dev, "The bus is still "
-                                               "active after timeout\n");
+                                       dev_err(&alg_data->adapter.dev,
+                                               "The bus is still active after timeout\n");
 
                        /* Disable master interrupts */
                        ctl = ioread32(I2C_REG_CTL(alg_data));
@@ -304,7 +303,7 @@ static int i2c_pnx_master_rcv(struct i2c_adapter *adap)
                }
        }
 
-       dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n",
+       dev_dbg(&alg_data->adapter.dev, "%s(): exiting: stat = %04x.\n",
                __func__, ioread32(I2C_REG_STS(alg_data)));
 
        return 0;
@@ -312,11 +311,11 @@ static int i2c_pnx_master_rcv(struct i2c_adapter *adap)
 
 static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
 {
+       struct i2c_pnx_algo_data *alg_data = dev_id;
        u32 stat, ctl;
-       struct i2c_adapter *adap = dev_id;
-       struct i2c_pnx_algo_data *alg_data = adap->algo_data;
 
-       dev_dbg(&adap->dev, "%s(): mstat = %x mctrl = %x, mode = %d\n",
+       dev_dbg(&alg_data->adapter.dev,
+               "%s(): mstat = %x mctrl = %x, mode = %d\n",
                __func__,
                ioread32(I2C_REG_STS(alg_data)),
                ioread32(I2C_REG_CTL(alg_data)),
@@ -339,10 +338,10 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
                complete(&alg_data->mif.complete);
        } else if (stat & mstatus_nai) {
                /* Slave did not acknowledge, generate a STOP */
-               dev_dbg(&adap->dev, "%s(): "
-                       "Slave did not acknowledge, generating a STOP.\n",
+               dev_dbg(&alg_data->adapter.dev,
+                       "%s(): Slave did not acknowledge, generating a STOP.\n",
                        __func__);
-               i2c_pnx_stop(adap);
+               i2c_pnx_stop(alg_data);
 
                /* Disable master interrupts. */
                ctl = ioread32(I2C_REG_CTL(alg_data));
@@ -368,9 +367,9 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
                 */
                if ((stat & mstatus_drmi) || !(stat & mstatus_rfe)) {
                        if (alg_data->mif.mode == I2C_SMBUS_WRITE) {
-                               i2c_pnx_master_xmit(adap);
+                               i2c_pnx_master_xmit(alg_data);
                        } else if (alg_data->mif.mode == I2C_SMBUS_READ) {
-                               i2c_pnx_master_rcv(adap);
+                               i2c_pnx_master_rcv(alg_data);
                        }
                }
        }
@@ -379,7 +378,8 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
        stat = ioread32(I2C_REG_STS(alg_data));
        iowrite32(stat | mstatus_tdi | mstatus_afi, I2C_REG_STS(alg_data));
 
-       dev_dbg(&adap->dev, "%s(): exiting, stat = %x ctrl = %x.\n",
+       dev_dbg(&alg_data->adapter.dev,
+               "%s(): exiting, stat = %x ctrl = %x.\n",
                 __func__, ioread32(I2C_REG_STS(alg_data)),
                 ioread32(I2C_REG_CTL(alg_data)));
 
@@ -388,14 +388,13 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
 
 static void i2c_pnx_timeout(unsigned long data)
 {
-       struct i2c_adapter *adap = (struct i2c_adapter *)data;
-       struct i2c_pnx_algo_data *alg_data = adap->algo_data;
+       struct i2c_pnx_algo_data *alg_data = (struct i2c_pnx_algo_data *)data;
        u32 ctl;
 
-       dev_err(&adap->dev, "Master timed out. stat = %04x, cntrl = %04x. "
-              "Resetting master...\n",
-              ioread32(I2C_REG_STS(alg_data)),
-              ioread32(I2C_REG_CTL(alg_data)));
+       dev_err(&alg_data->adapter.dev,
+               "Master timed out. stat = %04x, cntrl = %04x. Resetting master...\n",
+               ioread32(I2C_REG_STS(alg_data)),
+               ioread32(I2C_REG_CTL(alg_data)));
 
        /* Reset master and disable interrupts */
        ctl = ioread32(I2C_REG_CTL(alg_data));
@@ -409,15 +408,14 @@ static void i2c_pnx_timeout(unsigned long data)
        complete(&alg_data->mif.complete);
 }
 
-static inline void bus_reset_if_active(struct i2c_adapter *adap)
+static inline void bus_reset_if_active(struct i2c_pnx_algo_data *alg_data)
 {
-       struct i2c_pnx_algo_data *alg_data = adap->algo_data;
        u32 stat;
 
        if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_active) {
-               dev_err(&adap->dev,
+               dev_err(&alg_data->adapter.dev,
                        "%s: Bus is still active after xfer. Reset it...\n",
-                      adap->name);
+                       alg_data->adapter.name);
                iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
                          I2C_REG_CTL(alg_data));
                wait_reset(I2C_PNX_TIMEOUT, alg_data);
@@ -451,10 +449,11 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
        struct i2c_pnx_algo_data *alg_data = adap->algo_data;
        u32 stat = ioread32(I2C_REG_STS(alg_data));
 
-       dev_dbg(&adap->dev, "%s(): entering: %d messages, stat = %04x.\n",
+       dev_dbg(&alg_data->adapter.dev,
+               "%s(): entering: %d messages, stat = %04x.\n",
                __func__, num, ioread32(I2C_REG_STS(alg_data)));
 
-       bus_reset_if_active(adap);
+       bus_reset_if_active(alg_data);
 
        /* Process transactions in a loop. */
        for (i = 0; rc >= 0 && i < num; i++) {
@@ -464,9 +463,9 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
                addr = pmsg->addr;
 
                if (pmsg->flags & I2C_M_TEN) {
-                       dev_err(&adap->dev,
+                       dev_err(&alg_data->adapter.dev,
                                "%s: 10 bits addr not supported!\n",
-                               adap->name);
+                               alg_data->adapter.name);
                        rc = -EINVAL;
                        break;
                }
@@ -478,11 +477,10 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
                alg_data->mif.ret = 0;
                alg_data->last = (i == num - 1);
 
-               dev_dbg(&adap->dev, "%s(): mode %d, %d bytes\n", __func__,
-                       alg_data->mif.mode,
-                       alg_data->mif.len);
+               dev_dbg(&alg_data->adapter.dev, "%s(): mode %d, %d bytes\n",
+                       __func__, alg_data->mif.mode, alg_data->mif.len);
 
-               i2c_pnx_arm_timer(adap);
+               i2c_pnx_arm_timer(alg_data);
 
                /* initialize the completion var */
                init_completion(&alg_data->mif.complete);
@@ -493,7 +491,7 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
                          I2C_REG_CTL(alg_data));
 
                /* Put start-code and slave-address on the bus. */
-               rc = i2c_pnx_start(addr, adap);
+               rc = i2c_pnx_start(addr, alg_data);
                if (rc < 0)
                        break;
 
@@ -502,31 +500,32 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 
                if (!(rc = alg_data->mif.ret))
                        completed++;
-               dev_dbg(&adap->dev, "%s(): Complete, return code = %d.\n",
+               dev_dbg(&alg_data->adapter.dev,
+                       "%s(): Complete, return code = %d.\n",
                        __func__, rc);
 
                /* Clear TDI and AFI bits in case they are set. */
                if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_tdi) {
-                       dev_dbg(&adap->dev,
+                       dev_dbg(&alg_data->adapter.dev,
                                "%s: TDI still set... clearing now.\n",
-                              adap->name);
+                               alg_data->adapter.name);
                        iowrite32(stat, I2C_REG_STS(alg_data));
                }
                if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_afi) {
-                       dev_dbg(&adap->dev,
+                       dev_dbg(&alg_data->adapter.dev,
                                "%s: AFI still set... clearing now.\n",
-                              adap->name);
+                               alg_data->adapter.name);
                        iowrite32(stat, I2C_REG_STS(alg_data));
                }
        }
 
-       bus_reset_if_active(adap);
+       bus_reset_if_active(alg_data);
 
        /* Cleanup to be sure... */
        alg_data->mif.buf = NULL;
        alg_data->mif.len = 0;
 
-       dev_dbg(&adap->dev, "%s(): exiting, stat = %x\n",
+       dev_dbg(&alg_data->adapter.dev, "%s(): exiting, stat = %x\n",
                __func__, ioread32(I2C_REG_STS(alg_data)));
 
        if (completed != num)
@@ -545,69 +544,92 @@ static struct i2c_algorithm pnx_algorithm = {
        .functionality = i2c_pnx_func,
 };
 
+#ifdef CONFIG_PM
 static int i2c_pnx_controller_suspend(struct platform_device *pdev,
                                      pm_message_t state)
 {
-       struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev);
-       return i2c_pnx->suspend(pdev, state);
+       struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev);
+
+       /* FIXME: shouldn't this be clk_disable? */
+       clk_enable(alg_data->clk);
+
+       return 0;
 }
 
 static int i2c_pnx_controller_resume(struct platform_device *pdev)
 {
-       struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev);
-       return i2c_pnx->resume(pdev);
+       struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev);
+
+       return clk_enable(alg_data->clk);
 }
+#else
+#define i2c_pnx_controller_suspend     NULL
+#define i2c_pnx_controller_resume      NULL
+#endif
 
 static int __devinit i2c_pnx_probe(struct platform_device *pdev)
 {
        unsigned long tmp;
        int ret = 0;
        struct i2c_pnx_algo_data *alg_data;
-       int freq_mhz;
+       unsigned long freq;
        struct i2c_pnx_data *i2c_pnx = pdev->dev.platform_data;
 
-       if (!i2c_pnx || !i2c_pnx->adapter) {
+       if (!i2c_pnx || !i2c_pnx->name) {
                dev_err(&pdev->dev, "%s: no platform data supplied\n",
                       __func__);
                ret = -EINVAL;
                goto out;
        }
 
-       platform_set_drvdata(pdev, i2c_pnx);
-
-       if (i2c_pnx->calculate_input_freq)
-               freq_mhz = i2c_pnx->calculate_input_freq(pdev);
-       else {
-               freq_mhz = PNX_DEFAULT_FREQ;
-               dev_info(&pdev->dev, "Setting bus frequency to default value: "
-                      "%d MHz\n", freq_mhz);
+       alg_data = kzalloc(sizeof(*alg_data), GFP_KERNEL);
+       if (!alg_data) {
+               ret = -ENOMEM;
+               goto err_kzalloc;
        }
 
-       i2c_pnx->adapter->algo = &pnx_algorithm;
+       platform_set_drvdata(pdev, alg_data);
+
+       strlcpy(alg_data->adapter.name, i2c_pnx->name,
+               sizeof(alg_data->adapter.name));
+       alg_data->adapter.dev.parent = &pdev->dev;
+       alg_data->adapter.algo = &pnx_algorithm;
+       alg_data->adapter.algo_data = alg_data;
+       alg_data->adapter.nr = pdev->id;
+       alg_data->i2c_pnx = i2c_pnx;
+
+       alg_data->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(alg_data->clk)) {
+               ret = PTR_ERR(alg_data->clk);
+               goto out_drvdata;
+       }
 
-       alg_data = i2c_pnx->adapter->algo_data;
        init_timer(&alg_data->mif.timer);
        alg_data->mif.timer.function = i2c_pnx_timeout;
-       alg_data->mif.timer.data = (unsigned long)i2c_pnx->adapter;
+       alg_data->mif.timer.data = (unsigned long)alg_data;
 
        /* Register I/O resource */
-       if (!request_mem_region(alg_data->base, I2C_PNX_REGION_SIZE,
+       if (!request_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE,
                                pdev->name)) {
                dev_err(&pdev->dev,
                       "I/O region 0x%08x for I2C already in use.\n",
-                      alg_data->base);
+                      i2c_pnx->base);
                ret = -ENODEV;
-               goto out_drvdata;
+               goto out_clkget;
        }
 
-       if (!(alg_data->ioaddr =
-                       (u32)ioremap(alg_data->base, I2C_PNX_REGION_SIZE))) {
+       alg_data->ioaddr = ioremap(i2c_pnx->base, I2C_PNX_REGION_SIZE);
+       if (!alg_data->ioaddr) {
                dev_err(&pdev->dev, "Couldn't ioremap I2C I/O region\n");
                ret = -ENOMEM;
                goto out_release;
        }
 
-       i2c_pnx->set_clock_run(pdev);
+       ret = clk_enable(alg_data->clk);
+       if (ret)
+               goto out_unmap;
+
+       freq = clk_get_rate(alg_data->clk);
 
        /*
         * Clock Divisor High This value is the number of system clocks
@@ -620,45 +642,47 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev)
         * the deglitching filter length.
         */
 
-       tmp = ((freq_mhz * 1000) / I2C_PNX_SPEED_KHZ) / 2 - 2;
+       tmp = ((freq / 1000) / I2C_PNX_SPEED_KHZ) / 2 - 2;
        iowrite32(tmp, I2C_REG_CKH(alg_data));
        iowrite32(tmp, I2C_REG_CKL(alg_data));
 
        iowrite32(mcntrl_reset, I2C_REG_CTL(alg_data));
        if (wait_reset(I2C_PNX_TIMEOUT, alg_data)) {
                ret = -ENODEV;
-               goto out_unmap;
+               goto out_clock;
        }
        init_completion(&alg_data->mif.complete);
 
-       ret = request_irq(alg_data->irq, i2c_pnx_interrupt,
-                       0, pdev->name, i2c_pnx->adapter);
+       ret = request_irq(i2c_pnx->irq, i2c_pnx_interrupt,
+                       0, pdev->name, alg_data);
        if (ret)
                goto out_clock;
 
        /* Register this adapter with the I2C subsystem */
-       i2c_pnx->adapter->dev.parent = &pdev->dev;
-       i2c_pnx->adapter->nr = pdev->id;
-       ret = i2c_add_numbered_adapter(i2c_pnx->adapter);
+       ret = i2c_add_numbered_adapter(&alg_data->adapter);
        if (ret < 0) {
                dev_err(&pdev->dev, "I2C: Failed to add bus\n");
                goto out_irq;
        }
 
        dev_dbg(&pdev->dev, "%s: Master at %#8x, irq %d.\n",
-              i2c_pnx->adapter->name, alg_data->base, alg_data->irq);
+              alg_data->adapter.name, i2c_pnx->base, i2c_pnx->irq);
 
        return 0;
 
 out_irq:
-       free_irq(alg_data->irq, i2c_pnx->adapter);
+       free_irq(i2c_pnx->irq, alg_data);
 out_clock:
-       i2c_pnx->set_clock_stop(pdev);
+       clk_disable(alg_data->clk);
 out_unmap:
-       iounmap((void *)alg_data->ioaddr);
+       iounmap(alg_data->ioaddr);
 out_release:
-       release_mem_region(alg_data->base, I2C_PNX_REGION_SIZE);
+       release_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE);
+out_clkget:
+       clk_put(alg_data->clk);
 out_drvdata:
+       kfree(alg_data);
+err_kzalloc:
        platform_set_drvdata(pdev, NULL);
 out:
        return ret;
@@ -666,15 +690,16 @@ out:
 
 static int __devexit i2c_pnx_remove(struct platform_device *pdev)
 {
-       struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev);
-       struct i2c_adapter *adap = i2c_pnx->adapter;
-       struct i2c_pnx_algo_data *alg_data = adap->algo_data;
-
-       free_irq(alg_data->irq, i2c_pnx->adapter);
-       i2c_del_adapter(adap);
-       i2c_pnx->set_clock_stop(pdev);
-       iounmap((void *)alg_data->ioaddr);
-       release_mem_region(alg_data->base, I2C_PNX_REGION_SIZE);
+       struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev);
+       struct i2c_pnx_data *i2c_pnx = alg_data->i2c_pnx;
+
+       free_irq(i2c_pnx->irq, alg_data);
+       i2c_del_adapter(&alg_data->adapter);
+       clk_disable(alg_data->clk);
+       iounmap(alg_data->ioaddr);
+       release_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE);
+       clk_put(alg_data->clk);
+       kfree(alg_data);
        platform_set_drvdata(pdev, NULL);
 
        return 0;
index c0cf45a11b938cfd4b0d0bb84329535f8151172c..5cb01e5c323c993c08d0226d72c16815310febc7 100644 (file)
@@ -108,11 +108,11 @@ bool ide_port_acpi(ide_hwif_t *hwif)
  * Returns 0 on success, <0 on error.
  */
 static int ide_get_dev_handle(struct device *dev, acpi_handle *handle,
-                              acpi_integer *pcidevfn)
+                              u64 *pcidevfn)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        unsigned int bus, devnum, func;
-       acpi_integer addr;
+       u64 addr;
        acpi_handle dev_handle;
        acpi_status status;
        struct acpi_device_info *dinfo = NULL;
@@ -122,7 +122,7 @@ static int ide_get_dev_handle(struct device *dev, acpi_handle *handle,
        devnum = PCI_SLOT(pdev->devfn);
        func = PCI_FUNC(pdev->devfn);
        /* ACPI _ADR encoding for PCI bus: */
-       addr = (acpi_integer)(devnum << 16 | func);
+       addr = (u64)(devnum << 16 | func);
 
        DEBPRINT("ENTER: pci %02x:%02x.%01x\n", bus, devnum, func);
 
@@ -169,7 +169,7 @@ static acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif)
 {
        struct device           *dev = hwif->gendev.parent;
        acpi_handle             uninitialized_var(dev_handle);
-       acpi_integer            pcidevfn;
+       u64                     pcidevfn;
        acpi_handle             chan_handle;
        int                     err;
 
index 7f878017b736fcd913cfaea1e3939f10bb6cdf82..3b128dce9c3a15a203d3d7e13cb08bc9a14f283f 100644 (file)
@@ -679,7 +679,7 @@ static void ide_disk_setup(ide_drive_t *drive)
                if (max_s > hwif->rqsize)
                        max_s = hwif->rqsize;
 
-               blk_queue_max_sectors(q, max_s);
+               blk_queue_max_hw_sectors(q, max_s);
        }
 
        printk(KERN_INFO "%s: max request size: %dKiB\n", drive->name,
index fefbdfc8db068868afe0dadb0914a948219ea824..efd907623469fbc92a5e372fda19a4d6e260574d 100644 (file)
@@ -486,7 +486,7 @@ static void ide_floppy_setup(ide_drive_t *drive)
                drive->atapi_flags |= IDE_AFLAG_ZIP_DRIVE;
                /* This value will be visible in the /proc/ide/hdx/settings */
                drive->pc_delay = IDEFLOPPY_PC_DELAY;
-               blk_queue_max_sectors(drive->queue, 64);
+               blk_queue_max_hw_sectors(drive->queue, 64);
        }
 
        /*
@@ -494,7 +494,7 @@ static void ide_floppy_setup(ide_drive_t *drive)
         * nasty clicking noises without it, so please don't remove this.
         */
        if (strncmp((char *)&id[ATA_ID_PROD], "IOMEGA Clik!", 11) == 0) {
-               blk_queue_max_sectors(drive->queue, 64);
+               blk_queue_max_hw_sectors(drive->queue, 64);
                drive->atapi_flags |= IDE_AFLAG_CLIK_DRIVE;
                /* IOMEGA Clik! drives do not support lock/unlock commands */
                drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
index 4d76ba473097ac2ad89295181f9c8adb5433156a..f8c1ae6ad74c6b4ef46681e3942ce5c71b068fa5 100644 (file)
@@ -774,7 +774,7 @@ static int ide_init_queue(ide_drive_t *drive)
 
        if (hwif->rqsize < max_sectors)
                max_sectors = hwif->rqsize;
-       blk_queue_max_sectors(q, max_sectors);
+       blk_queue_max_hw_sectors(q, max_sectors);
 
 #ifdef CONFIG_PCI
        /* When we have an IOMMU, we may have a problem where pci_map_sg()
@@ -790,8 +790,7 @@ static int ide_init_queue(ide_drive_t *drive)
                max_sg_entries >>= 1;
 #endif /* CONFIG_PCI */
 
-       blk_queue_max_hw_segments(q, max_sg_entries);
-       blk_queue_max_phys_segments(q, max_sg_entries);
+       blk_queue_max_segments(q, max_sg_entries);
 
        /* assign drive queue */
        drive->queue = q;
index f199896c41135c7b3117ef96b571dff01f72394c..c88696a6cf8aa8a5d79b726f3b22ac3790837f67 100644 (file)
@@ -2020,7 +2020,7 @@ static int sbp2scsi_slave_configure(struct scsi_device *sdev)
        if (lu->workarounds & SBP2_WORKAROUND_POWER_CONDITION)
                sdev->start_stop_pwr_cond = 1;
        if (lu->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS)
-               blk_queue_max_sectors(sdev->request_queue, 128 * 1024 / 512);
+               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;
index 258c639571b5058bc9fece65f2de501cc0a25d75..9f9816baeb97bed74092781e35373ecae1a996ab 100644 (file)
@@ -278,6 +278,8 @@ static int evdev_open(struct inode *inode, struct file *file)
                goto err_free_client;
 
        file->private_data = client;
+       nonseekable_open(inode, file);
+
        return 0;
 
  err_free_client:
index b04930f7ea7da88e36e65a9c9faa9f188778de93..7392992da4243c35e127466035e1f35cb377af3a 100644 (file)
@@ -46,7 +46,7 @@ struct emu {
        int size;
 };
 
-static struct pci_device_id emu_tbl[] = {
+static const struct pci_device_id emu_tbl[] = {
 
        { 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live gameport */
        { 0x1102, 0x7003, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy gameport */
index 8a1810f88b9e4707b718b8ef6baebf0e98b47b41..14d3f3e208a2f557a80156dbe51c29f8aa0a0773 100644 (file)
@@ -140,7 +140,7 @@ static void __devexit fm801_gp_remove(struct pci_dev *pci)
        }
 }
 
-static struct pci_device_id fm801_gp_id_table[] = {
+static const struct pci_device_id fm801_gp_id_table[] = {
        { PCI_VENDOR_ID_FORTEMEDIA, PCI_DEVICE_ID_FM801_GP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0  },
        { 0 }
 };
index ac11be08585e9fc70d75e466ebd9942006c78d0f..7e18bcf05a662353d395d7a7c527c61271eed097 100644 (file)
@@ -11,6 +11,8 @@
  * the Free Software Foundation.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/stddef.h>
 #include <linux/module.h>
 #include <linux/ioport.h>
@@ -190,9 +192,8 @@ static int gameport_bind_driver(struct gameport *gameport, struct gameport_drive
 
        error = device_bind_driver(&gameport->dev);
        if (error) {
-               printk(KERN_WARNING
-                       "gameport: device_bind_driver() failed "
-                       "for %s (%s) and %s, error: %d\n",
+               dev_warn(&gameport->dev,
+                        "device_bind_driver() failed for %s (%s) and %s, error: %d\n",
                        gameport->phys, gameport->name,
                        drv->description, error);
                drv->disconnect(gameport);
@@ -209,9 +210,9 @@ static void gameport_find_driver(struct gameport *gameport)
 
        error = device_attach(&gameport->dev);
        if (error < 0)
-               printk(KERN_WARNING
-                       "gameport: device_attach() failed for %s (%s), error: %d\n",
-                       gameport->phys, gameport->name, error);
+               dev_warn(&gameport->dev,
+                        "device_attach() failed for %s (%s), error: %d\n",
+                        gameport->phys, gameport->name, error);
 }
 
 
@@ -262,17 +263,14 @@ static int gameport_queue_event(void *object, struct module *owner,
 
        event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC);
        if (!event) {
-               printk(KERN_ERR
-                       "gameport: Not enough memory to queue event %d\n",
-                       event_type);
+               pr_err("Not enough memory to queue event %d\n", event_type);
                retval = -ENOMEM;
                goto out;
        }
 
        if (!try_module_get(owner)) {
-               printk(KERN_WARNING
-                       "gameport: Can't get module reference, dropping event %d\n",
-                       event_type);
+               pr_warning("Can't get module reference, dropping event %d\n",
+                          event_type);
                kfree(event);
                retval = -EINVAL;
                goto out;
@@ -298,14 +296,12 @@ static void gameport_free_event(struct gameport_event *event)
 
 static void gameport_remove_duplicate_events(struct gameport_event *event)
 {
-       struct list_head *node, *next;
-       struct gameport_event *e;
+       struct gameport_event *e, *next;
        unsigned long flags;
 
        spin_lock_irqsave(&gameport_event_lock, flags);
 
-       list_for_each_safe(node, next, &gameport_event_list) {
-               e = list_entry(node, struct gameport_event, node);
+       list_for_each_entry_safe(e, next, &gameport_event_list, node) {
                if (event->object == e->object) {
                        /*
                         * If this event is of different type we should not
@@ -315,7 +311,7 @@ static void gameport_remove_duplicate_events(struct gameport_event *event)
                        if (event->type != e->type)
                                break;
 
-                       list_del_init(node);
+                       list_del_init(&e->node);
                        gameport_free_event(e);
                }
        }
@@ -325,23 +321,18 @@ static void gameport_remove_duplicate_events(struct gameport_event *event)
 
 static struct gameport_event *gameport_get_event(void)
 {
-       struct gameport_event *event;
-       struct list_head *node;
+       struct gameport_event *event = NULL;
        unsigned long flags;
 
        spin_lock_irqsave(&gameport_event_lock, flags);
 
-       if (list_empty(&gameport_event_list)) {
-               spin_unlock_irqrestore(&gameport_event_lock, flags);
-               return NULL;
+       if (!list_empty(&gameport_event_list)) {
+               event = list_first_entry(&gameport_event_list,
+                                        struct gameport_event, node);
+               list_del_init(&event->node);
        }
 
-       node = gameport_event_list.next;
-       event = list_entry(node, struct gameport_event, node);
-       list_del_init(node);
-
        spin_unlock_irqrestore(&gameport_event_lock, flags);
-
        return event;
 }
 
@@ -360,16 +351,14 @@ static void gameport_handle_event(void)
        if ((event = gameport_get_event())) {
 
                switch (event->type) {
-                       case GAMEPORT_REGISTER_PORT:
-                               gameport_add_port(event->object);
-                               break;
 
-                       case GAMEPORT_ATTACH_DRIVER:
-                               gameport_attach_driver(event->object);
-                               break;
+               case GAMEPORT_REGISTER_PORT:
+                       gameport_add_port(event->object);
+                       break;
 
-                       default:
-                               break;
+               case GAMEPORT_ATTACH_DRIVER:
+                       gameport_attach_driver(event->object);
+                       break;
                }
 
                gameport_remove_duplicate_events(event);
@@ -385,16 +374,14 @@ static void gameport_handle_event(void)
  */
 static void gameport_remove_pending_events(void *object)
 {
-       struct list_head *node, *next;
-       struct gameport_event *event;
+       struct gameport_event *event, *next;
        unsigned long flags;
 
        spin_lock_irqsave(&gameport_event_lock, flags);
 
-       list_for_each_safe(node, next, &gameport_event_list) {
-               event = list_entry(node, struct gameport_event, node);
+       list_for_each_entry_safe(event, next, &gameport_event_list, node) {
                if (event->object == object) {
-                       list_del_init(node);
+                       list_del_init(&event->node);
                        gameport_free_event(event);
                }
        }
@@ -441,7 +428,6 @@ static int gameport_thread(void *nothing)
                        kthread_should_stop() || !list_empty(&gameport_event_list));
        } while (!kthread_should_stop());
 
-       printk(KERN_DEBUG "gameport: kgameportd exiting\n");
        return 0;
 }
 
@@ -453,6 +439,7 @@ static int gameport_thread(void *nothing)
 static ssize_t gameport_show_description(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct gameport *gameport = to_gameport_port(dev);
+
        return sprintf(buf, "%s\n", gameport->name);
 }
 
@@ -521,7 +508,8 @@ static void gameport_init_port(struct gameport *gameport)
 
        mutex_init(&gameport->drv_mutex);
        device_initialize(&gameport->dev);
-       dev_set_name(&gameport->dev, "gameport%lu", (unsigned long)atomic_inc_return(&gameport_no) - 1);
+       dev_set_name(&gameport->dev, "gameport%lu",
+                       (unsigned long)atomic_inc_return(&gameport_no) - 1);
        gameport->dev.bus = &gameport_bus;
        gameport->dev.release = gameport_release_port;
        if (gameport->parent)
@@ -550,19 +538,17 @@ static void gameport_add_port(struct gameport *gameport)
        list_add_tail(&gameport->node, &gameport_list);
 
        if (gameport->io)
-               printk(KERN_INFO "gameport: %s is %s, io %#x, speed %dkHz\n",
-                       gameport->name, gameport->phys, gameport->io, gameport->speed);
+               dev_info(&gameport->dev, "%s is %s, io %#x, speed %dkHz\n",
+                        gameport->name, gameport->phys, gameport->io, gameport->speed);
        else
-               printk(KERN_INFO "gameport: %s is %s, speed %dkHz\n",
+               dev_info(&gameport->dev, "%s is %s, speed %dkHz\n",
                        gameport->name, gameport->phys, gameport->speed);
 
        error = device_add(&gameport->dev);
        if (error)
-               printk(KERN_ERR
-                       "gameport: device_add() failed for %s (%s), error: %d\n",
+               dev_err(&gameport->dev,
+                       "device_add() failed for %s (%s), error: %d\n",
                        gameport->phys, gameport->name, error);
-       else
-               gameport->registered = 1;
 }
 
 /*
@@ -584,10 +570,8 @@ static void gameport_destroy_port(struct gameport *gameport)
                gameport->parent = NULL;
        }
 
-       if (gameport->registered) {
+       if (device_is_registered(&gameport->dev))
                device_del(&gameport->dev);
-               gameport->registered = 0;
-       }
 
        list_del_init(&gameport->node);
 
@@ -705,8 +689,7 @@ static void gameport_attach_driver(struct gameport_driver *drv)
 
        error = driver_attach(&drv->driver);
        if (error)
-               printk(KERN_ERR
-                       "gameport: driver_attach() failed for %s, error: %d\n",
+               pr_err("driver_attach() failed for %s, error: %d\n",
                        drv->driver.name, error);
 }
 
@@ -727,8 +710,7 @@ int __gameport_register_driver(struct gameport_driver *drv, struct module *owner
 
        error = driver_register(&drv->driver);
        if (error) {
-               printk(KERN_ERR
-                       "gameport: driver_register() failed for %s, error: %d\n",
+               pr_err("driver_register() failed for %s, error: %d\n",
                        drv->driver.name, error);
                return error;
        }
@@ -828,7 +810,7 @@ static int __init gameport_init(void)
 
        error = bus_register(&gameport_bus);
        if (error) {
-               printk(KERN_ERR "gameport: failed to register gameport bus, error: %d\n", error);
+               pr_err("failed to register gameport bus, error: %d\n", error);
                return error;
        }
 
@@ -836,7 +818,7 @@ static int __init gameport_init(void)
        if (IS_ERR(gameport_task)) {
                bus_unregister(&gameport_bus);
                error = PTR_ERR(gameport_task);
-               printk(KERN_ERR "gameport: Failed to start kgameportd, error: %d\n", error);
+               pr_err("Failed to start kgameportd, error: %d\n", error);
                return error;
        }
 
index db556b71dddadc609568fbb772f0f6379a20b381..7c217848613ef2a0e2367bf32f36c5b7ed63e1d7 100644 (file)
@@ -166,7 +166,7 @@ static int ns558_isa_probe(int io)
 
 #ifdef CONFIG_PNP
 
-static struct pnp_device_id pnp_devids[] = {
+static const struct pnp_device_id pnp_devids[] = {
        { .id = "@P@0001", .driver_data = 0 }, /* ALS 100 */
        { .id = "@P@0020", .driver_data = 0 }, /* ALS 200 */
        { .id = "@P@1001", .driver_data = 0 }, /* ALS 100+ */
index 47cd9eaee66a6b7ef4cd2b706ec05611681fff68..4d8ea32e8a001847746a796c43cf79dc70ae3c3c 100644 (file)
@@ -21,8 +21,6 @@
    you why the ifdefs are needed? Think about it again. -AK */
 #ifdef CONFIG_X86_64
 #  define INPUT_COMPAT_TEST is_compat_task()
-#elif defined(CONFIG_IA64)
-#  define INPUT_COMPAT_TEST IS_IA32_PROCESS(task_pt_regs(current))
 #elif defined(CONFIG_S390)
 #  define INPUT_COMPAT_TEST test_thread_flag(TIF_31BIT)
 #elif defined(CONFIG_MIPS)
index 86cb2d2196ff9792f18c39646e44983af46fcf61..41168d5f8c17bb0d1847b03695db8c095565ade5 100644 (file)
@@ -87,12 +87,14 @@ static int input_defuzz_abs_event(int value, int old_val, int fuzz)
 }
 
 /*
- * Pass event through all open handles. This function is called with
+ * Pass event first through all filters and then, if event has not been
+ * filtered out, through all open handles. This function is called with
  * dev->event_lock held and interrupts disabled.
  */
 static void input_pass_event(struct input_dev *dev,
                             unsigned int type, unsigned int code, int value)
 {
+       struct input_handler *handler;
        struct input_handle *handle;
 
        rcu_read_lock();
@@ -100,11 +102,25 @@ static void input_pass_event(struct input_dev *dev,
        handle = rcu_dereference(dev->grab);
        if (handle)
                handle->handler->event(handle, type, code, value);
-       else
-               list_for_each_entry_rcu(handle, &dev->h_list, d_node)
-                       if (handle->open)
-                               handle->handler->event(handle,
-                                                       type, code, value);
+       else {
+               bool filtered = false;
+
+               list_for_each_entry_rcu(handle, &dev->h_list, d_node) {
+                       if (!handle->open)
+                               continue;
+
+                       handler = handle->handler;
+                       if (!handler->filter) {
+                               if (filtered)
+                                       break;
+
+                               handler->event(handle, type, code, value);
+
+                       } else if (handler->filter(handle, type, code, value))
+                               filtered = true;
+               }
+       }
+
        rcu_read_unlock();
 }
 
@@ -615,12 +631,12 @@ static int input_default_setkeycode(struct input_dev *dev,
                }
        }
 
-       clear_bit(old_keycode, dev->keybit);
-       set_bit(keycode, dev->keybit);
+       __clear_bit(old_keycode, dev->keybit);
+       __set_bit(keycode, dev->keybit);
 
        for (i = 0; i < dev->keycodemax; i++) {
                if (input_fetch_keycode(dev, i) == old_keycode) {
-                       set_bit(old_keycode, dev->keybit);
+                       __set_bit(old_keycode, dev->keybit);
                        break; /* Setting the bit twice is useless, so break */
                }
        }
@@ -678,6 +694,9 @@ int input_set_keycode(struct input_dev *dev, int scancode, int keycode)
        if (retval)
                goto out;
 
+       /* Make sure KEY_RESERVED did not get enabled. */
+       __clear_bit(KEY_RESERVED, dev->keybit);
+
        /*
         * Simulate keyup event if keycode is not present
         * in the keymap anymore
@@ -705,12 +724,13 @@ EXPORT_SYMBOL(input_set_keycode);
                if (i != BITS_TO_LONGS(max)) \
                        continue;
 
-static const struct input_device_id *input_match_device(const struct input_device_id *id,
+static const struct input_device_id *input_match_device(struct input_handler *handler,
                                                        struct input_dev *dev)
 {
+       const struct input_device_id *id;
        int i;
 
-       for (; id->flags || id->driver_info; id++) {
+       for (id = handler->id_table; id->flags || id->driver_info; id++) {
 
                if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)
                        if (id->bustype != dev->id.bustype)
@@ -738,7 +758,8 @@ static const struct input_device_id *input_match_device(const struct input_devic
                MATCH_BIT(ffbit,  FF_MAX);
                MATCH_BIT(swbit,  SW_MAX);
 
-               return id;
+               if (!handler->match || handler->match(handler, dev))
+                       return id;
        }
 
        return NULL;
@@ -749,10 +770,7 @@ static int input_attach_handler(struct input_dev *dev, struct input_handler *han
        const struct input_device_id *id;
        int error;
 
-       if (handler->blacklist && input_match_device(handler->blacklist, dev))
-               return -ENODEV;
-
-       id = input_match_device(handler->id_table, dev);
+       id = input_match_device(handler, dev);
        if (!id)
                return -ENODEV;
 
@@ -988,6 +1006,8 @@ static int input_handlers_seq_show(struct seq_file *seq, void *v)
        union input_seq_state *state = (union input_seq_state *)&seq->private;
 
        seq_printf(seq, "N: Number=%u Name=%s", state->pos, handler->name);
+       if (handler->filter)
+               seq_puts(seq, " (filter)");
        if (handler->fops)
                seq_printf(seq, " Minor=%d", handler->minor);
        seq_putc(seq, '\n');
@@ -1551,6 +1571,25 @@ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int
 }
 EXPORT_SYMBOL(input_set_capability);
 
+#define INPUT_CLEANSE_BITMASK(dev, type, bits)                         \
+       do {                                                            \
+               if (!test_bit(EV_##type, dev->evbit))                   \
+                       memset(dev->bits##bit, 0,                       \
+                               sizeof(dev->bits##bit));                \
+       } while (0)
+
+static void input_cleanse_bitmasks(struct input_dev *dev)
+{
+       INPUT_CLEANSE_BITMASK(dev, KEY, key);
+       INPUT_CLEANSE_BITMASK(dev, REL, rel);
+       INPUT_CLEANSE_BITMASK(dev, ABS, abs);
+       INPUT_CLEANSE_BITMASK(dev, MSC, msc);
+       INPUT_CLEANSE_BITMASK(dev, LED, led);
+       INPUT_CLEANSE_BITMASK(dev, SND, snd);
+       INPUT_CLEANSE_BITMASK(dev, FF, ff);
+       INPUT_CLEANSE_BITMASK(dev, SW, sw);
+}
+
 /**
  * input_register_device - register device with input core
  * @dev: device to be registered
@@ -1570,13 +1609,19 @@ int input_register_device(struct input_dev *dev)
        const char *path;
        int error;
 
+       /* Every input device generates EV_SYN/SYN_REPORT events. */
        __set_bit(EV_SYN, dev->evbit);
 
+       /* KEY_RESERVED is not supposed to be transmitted to userspace. */
+       __clear_bit(KEY_RESERVED, dev->keybit);
+
+       /* Make sure that bitmasks not mentioned in dev->evbit are clean. */
+       input_cleanse_bitmasks(dev);
+
        /*
         * If delay and period are pre-set by the driver, then autorepeating
         * is handled by the driver itself and we don't do it in input.c.
         */
-
        init_timer(&dev->timer);
        if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
                dev->timer.data = (long) dev;
@@ -1776,7 +1821,16 @@ int input_register_handle(struct input_handle *handle)
        error = mutex_lock_interruptible(&dev->mutex);
        if (error)
                return error;
-       list_add_tail_rcu(&handle->d_node, &dev->h_list);
+
+       /*
+        * Filters go to the head of the list, normal handlers
+        * to the tail.
+        */
+       if (handler->filter)
+               list_add_rcu(&handle->d_node, &dev->h_list);
+       else
+               list_add_tail_rcu(&handle->d_node, &dev->h_list);
+
        mutex_unlock(&dev->mutex);
 
        /*
index b1bd6dd322864d0bd04c2f9a48c9f80b3217dcce..c52bec4d0530f632667031e023e980e78dc4fcaf 100644 (file)
@@ -286,6 +286,8 @@ static int joydev_open(struct inode *inode, struct file *file)
                goto err_free_client;
 
        file->private_data = client;
+       nonseekable_open(inode, file);
+
        return 0;
 
  err_free_client:
@@ -775,6 +777,20 @@ static void joydev_cleanup(struct joydev *joydev)
                input_close_device(handle);
 }
 
+
+static bool joydev_match(struct input_handler *handler, struct input_dev *dev)
+{
+       /* Avoid touchpads and touchscreens */
+       if (test_bit(EV_KEY, dev->evbit) && test_bit(BTN_TOUCH, dev->keybit))
+               return false;
+
+       /* Avoid tablets, digitisers and similar devices */
+       if (test_bit(EV_KEY, dev->evbit) && test_bit(BTN_DIGI, dev->keybit))
+               return false;
+
+       return true;
+}
+
 static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
                          const struct input_device_id *id)
 {
@@ -894,22 +910,6 @@ static void joydev_disconnect(struct input_handle *handle)
        put_device(&joydev->dev);
 }
 
-static const struct input_device_id joydev_blacklist[] = {
-       {
-               .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
-                               INPUT_DEVICE_ID_MATCH_KEYBIT,
-               .evbit = { BIT_MASK(EV_KEY) },
-               .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) },
-       },      /* Avoid itouchpads and touchscreens */
-       {
-               .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
-                               INPUT_DEVICE_ID_MATCH_KEYBIT,
-               .evbit = { BIT_MASK(EV_KEY) },
-               .keybit = { [BIT_WORD(BTN_DIGI)] = BIT_MASK(BTN_DIGI) },
-       },      /* Avoid tablets, digitisers and similar devices */
-       { }     /* Terminating entry */
-};
-
 static const struct input_device_id joydev_ids[] = {
        {
                .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
@@ -936,13 +936,13 @@ MODULE_DEVICE_TABLE(input, joydev_ids);
 
 static struct input_handler joydev_handler = {
        .event          = joydev_event,
+       .match          = joydev_match,
        .connect        = joydev_connect,
        .disconnect     = joydev_disconnect,
        .fops           = &joydev_fops,
        .minor          = JOYDEV_MINOR_BASE,
        .name           = "joydev",
        .id_table       = joydev_ids,
-       .blacklist      = joydev_blacklist,
 };
 
 static int __init joydev_init(void)
index b11419590cfe21e61da8324f233d86fcf7a12209..5b596165b571f72976aeedd30fc6ee5eb6442994 100644 (file)
@@ -221,6 +221,7 @@ config JOYSTICK_DB9
 config JOYSTICK_GAMECON
        tristate "Multisystem, NES, SNES, N64, PSX joysticks and gamepads"
        depends on PARPORT
+       select INPUT_FF_MEMLESS
        ---help---
          Say Y here if you have a Nintendo Entertainment System gamepad,
          Super Nintendo Entertainment System gamepad, Nintendo 64 gamepad,
index 07a32aff5a31340cdd87b6285d77f041326f73aa..ae998d99a5ae619b87d66bd8e20ebf5c1c2a5571 100644 (file)
@@ -30,6 +30,8 @@
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/module.h>
@@ -61,48 +63,73 @@ MODULE_PARM_DESC(map3, "Describes third set of devices");
 
 /* see also gs_psx_delay parameter in PSX support section */
 
-#define GC_SNES                1
-#define GC_NES         2
-#define GC_NES4                3
-#define GC_MULTI       4
-#define GC_MULTI2      5
-#define GC_N64         6
-#define GC_PSX         7
-#define GC_DDR         8
-#define GC_SNESMOUSE   9
-
-#define GC_MAX         9
+enum gc_type {
+       GC_NONE = 0,
+       GC_SNES,
+       GC_NES,
+       GC_NES4,
+       GC_MULTI,
+       GC_MULTI2,
+       GC_N64,
+       GC_PSX,
+       GC_DDR,
+       GC_SNESMOUSE,
+       GC_MAX
+};
 
 #define GC_REFRESH_TIME        HZ/100
 
+struct gc_pad {
+       struct input_dev *dev;
+       enum gc_type type;
+       char phys[32];
+};
+
 struct gc {
        struct pardevice *pd;
+       struct gc_pad pads[GC_MAX_DEVICES];
        struct input_dev *dev[GC_MAX_DEVICES];
        struct timer_list timer;
-       unsigned char pads[GC_MAX + 1];
+       int pad_count[GC_MAX];
        int used;
        struct mutex mutex;
-       char phys[GC_MAX_DEVICES][32];
+};
+
+struct gc_subdev {
+       unsigned int idx;
 };
 
 static struct gc *gc_base[3];
 
-static int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 };
+static const int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 };
+
+static const char *gc_names[] = {
+       NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick",
+       "Multisystem 2-button joystick", "N64 controller", "PSX controller",
+       "PSX DDR controller", "SNES mouse"
+};
 
-static char *gc_names[] = { NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick",
-                               "Multisystem 2-button joystick", "N64 controller", "PSX controller",
-                               "PSX DDR controller", "SNES mouse" };
 /*
  * N64 support.
  */
 
-static unsigned char gc_n64_bytes[] = { 0, 1, 13, 15, 14, 12, 10, 11, 2, 3 };
-static short gc_n64_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_TRIGGER, BTN_START };
+static const unsigned char gc_n64_bytes[] = { 0, 1, 13, 15, 14, 12, 10, 11, 2, 3 };
+static const short gc_n64_btn[] = {
+       BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z,
+       BTN_TL, BTN_TR, BTN_TRIGGER, BTN_START
+};
 
 #define GC_N64_LENGTH          32              /* N64 bit length, not including stop bit */
-#define GC_N64_REQUEST_LENGTH  37              /* transmit request sequence is 9 bits long */
+#define GC_N64_STOP_LENGTH     5               /* Length of encoded stop bit */
+#define GC_N64_CMD_00          0x11111111UL
+#define GC_N64_CMD_01          0xd1111111UL
+#define GC_N64_CMD_03          0xdd111111UL
+#define GC_N64_CMD_1b          0xdd1dd111UL
+#define GC_N64_CMD_c0          0x111111ddUL
+#define GC_N64_CMD_80          0x1111111dUL
+#define GC_N64_STOP_BIT                0x1d            /* Encoded stop bit */
+#define GC_N64_REQUEST_DATA    GC_N64_CMD_01   /* the request data command */
 #define GC_N64_DELAY           133             /* delay between transmit request, and response ready (us) */
-#define GC_N64_REQUEST         0x1dd1111111ULL /* the request data command (encoded for 000000011) */
 #define GC_N64_DWS             3               /* delay between write segments (required for sound playback because of ISA DMA) */
                                                /* GC_N64_DWS > 24 is known to fail */
 #define GC_N64_POWER_W         0xe2            /* power during write (transmit request) */
@@ -113,9 +140,41 @@ static short gc_n64_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL,
                                                /* than 123 us */
 #define GC_N64_CLOCK           0x02            /* clock bits for read */
 
+/*
+ * Used for rumble code.
+ */
+
+/* Send encoded command */
+static void gc_n64_send_command(struct gc *gc, unsigned long cmd,
+                               unsigned char target)
+{
+       struct parport *port = gc->pd->port;
+       int i;
+
+       for (i = 0; i < GC_N64_LENGTH; i++) {
+               unsigned char data = (cmd >> i) & 1 ? target : 0;
+               parport_write_data(port, GC_N64_POWER_W | data);
+               udelay(GC_N64_DWS);
+       }
+}
+
+/* Send stop bit */
+static void gc_n64_send_stop_bit(struct gc *gc, unsigned char target)
+{
+       struct parport *port = gc->pd->port;
+       int i;
+
+       for (i = 0; i < GC_N64_STOP_LENGTH; i++) {
+               unsigned char data = (GC_N64_STOP_BIT >> i) & 1 ? target : 0;
+               parport_write_data(port, GC_N64_POWER_W | data);
+               udelay(GC_N64_DWS);
+       }
+}
+
 /*
  * gc_n64_read_packet() reads an N64 packet.
- * Each pad uses one bit per byte. So all pads connected to this port are read in parallel.
+ * Each pad uses one bit per byte. So all pads connected to this port
+ * are read in parallel.
  */
 
 static void gc_n64_read_packet(struct gc *gc, unsigned char *data)
@@ -128,14 +187,13 @@ static void gc_n64_read_packet(struct gc *gc, unsigned char *data)
  */
 
        local_irq_save(flags);
-       for (i = 0; i < GC_N64_REQUEST_LENGTH; i++) {
-               parport_write_data(gc->pd->port, GC_N64_POWER_W | ((GC_N64_REQUEST >> i) & 1 ? GC_N64_OUT : 0));
-               udelay(GC_N64_DWS);
-       }
+       gc_n64_send_command(gc, GC_N64_REQUEST_DATA, GC_N64_OUT);
+       gc_n64_send_stop_bit(gc, GC_N64_OUT);
        local_irq_restore(flags);
 
 /*
- * Wait for the pad response to be loaded into the 33-bit register of the adapter
+ * Wait for the pad response to be loaded into the 33-bit register
+ * of the adapter.
  */
 
        udelay(GC_N64_DELAY);
@@ -146,13 +204,15 @@ static void gc_n64_read_packet(struct gc *gc, unsigned char *data)
 
        for (i = 0; i < GC_N64_LENGTH; i++) {
                parport_write_data(gc->pd->port, GC_N64_POWER_R);
+               udelay(2);
                data[i] = parport_read_status(gc->pd->port);
                parport_write_data(gc->pd->port, GC_N64_POWER_R | GC_N64_CLOCK);
         }
 
 /*
- * We must wait 200 ms here for the controller to reinitialize before the next read request.
- * No worries as long as gc_read is polled less frequently than this.
+ * We must wait 200 ms here for the controller to reinitialize before
+ * the next read request. No worries as long as gc_read is polled less
+ * frequently than this.
  */
 
 }
@@ -160,45 +220,112 @@ static void gc_n64_read_packet(struct gc *gc, unsigned char *data)
 static void gc_n64_process_packet(struct gc *gc)
 {
        unsigned char data[GC_N64_LENGTH];
-       signed char axes[2];
        struct input_dev *dev;
        int i, j, s;
+       signed char x, y;
 
        gc_n64_read_packet(gc, data);
 
        for (i = 0; i < GC_MAX_DEVICES; i++) {
 
-               dev = gc->dev[i];
-               if (!dev)
+               if (gc->pads[i].type != GC_N64)
                        continue;
 
+               dev = gc->pads[i].dev;
                s = gc_status_bit[i];
 
-               if (s & gc->pads[GC_N64] & ~(data[8] | data[9])) {
+               if (s & ~(data[8] | data[9])) {
 
-                       axes[0] = axes[1] = 0;
+                       x = y = 0;
 
                        for (j = 0; j < 8; j++) {
                                if (data[23 - j] & s)
-                                       axes[0] |= 1 << j;
+                                       x |= 1 << j;
                                if (data[31 - j] & s)
-                                       axes[1] |= 1 << j;
+                                       y |= 1 << j;
                        }
 
-                       input_report_abs(dev, ABS_X,  axes[0]);
-                       input_report_abs(dev, ABS_Y, -axes[1]);
+                       input_report_abs(dev, ABS_X,  x);
+                       input_report_abs(dev, ABS_Y, -y);
 
-                       input_report_abs(dev, ABS_HAT0X, !(s & data[6]) - !(s & data[7]));
-                       input_report_abs(dev, ABS_HAT0Y, !(s & data[4]) - !(s & data[5]));
+                       input_report_abs(dev, ABS_HAT0X,
+                                        !(s & data[6]) - !(s & data[7]));
+                       input_report_abs(dev, ABS_HAT0Y,
+                                        !(s & data[4]) - !(s & data[5]));
 
                        for (j = 0; j < 10; j++)
-                               input_report_key(dev, gc_n64_btn[j], s & data[gc_n64_bytes[j]]);
+                               input_report_key(dev, gc_n64_btn[j],
+                                                s & data[gc_n64_bytes[j]]);
 
                        input_sync(dev);
                }
        }
 }
 
+static int gc_n64_play_effect(struct input_dev *dev, void *data,
+                             struct ff_effect *effect)
+{
+       int i;
+       unsigned long flags;
+       struct gc *gc = input_get_drvdata(dev);
+       struct gc_subdev *sdev = data;
+       unsigned char target = 1 << sdev->idx; /* select desired pin */
+
+       if (effect->type == FF_RUMBLE) {
+               struct ff_rumble_effect *rumble = &effect->u.rumble;
+               unsigned int cmd =
+                       rumble->strong_magnitude || rumble->weak_magnitude ?
+                       GC_N64_CMD_01 : GC_N64_CMD_00;
+
+               local_irq_save(flags);
+
+               /* Init Rumble - 0x03, 0x80, 0x01, (34)0x80 */
+               gc_n64_send_command(gc, GC_N64_CMD_03, target);
+               gc_n64_send_command(gc, GC_N64_CMD_80, target);
+               gc_n64_send_command(gc, GC_N64_CMD_01, target);
+               for (i = 0; i < 32; i++)
+                       gc_n64_send_command(gc, GC_N64_CMD_80, target);
+               gc_n64_send_stop_bit(gc, target);
+
+               udelay(GC_N64_DELAY);
+
+               /* Now start or stop it - 0x03, 0xc0, 0zx1b, (32)0x01/0x00 */
+               gc_n64_send_command(gc, GC_N64_CMD_03, target);
+               gc_n64_send_command(gc, GC_N64_CMD_c0, target);
+               gc_n64_send_command(gc, GC_N64_CMD_1b, target);
+               for (i = 0; i < 32; i++)
+                       gc_n64_send_command(gc, cmd, target);
+               gc_n64_send_stop_bit(gc, target);
+
+               local_irq_restore(flags);
+
+       }
+
+       return 0;
+}
+
+static int __init gc_n64_init_ff(struct input_dev *dev, int i)
+{
+       struct gc_subdev *sdev;
+       int err;
+
+       sdev = kmalloc(sizeof(*sdev), GFP_KERNEL);
+       if (!sdev)
+               return -ENOMEM;
+
+       sdev->idx = i;
+
+       input_set_capability(dev, EV_FF, FF_RUMBLE);
+
+       err = input_ff_create_memless(dev, sdev, gc_n64_play_effect);
+       if (err) {
+               kfree(sdev);
+               return err;
+       }
+
+       return 0;
+}
+
 /*
  * NES/SNES support.
  */
@@ -214,9 +341,11 @@ static void gc_n64_process_packet(struct gc *gc)
 #define GC_NES_CLOCK   0x01
 #define GC_NES_LATCH   0x02
 
-static unsigned char gc_nes_bytes[] = { 0, 1, 2, 3 };
-static unsigned char gc_snes_bytes[] = { 8, 0, 2, 3, 9, 1, 10, 11 };
-static short gc_snes_btn[] = { BTN_A, BTN_B, BTN_SELECT, BTN_START, BTN_X, BTN_Y, BTN_TL, BTN_TR };
+static const unsigned char gc_nes_bytes[] = { 0, 1, 2, 3 };
+static const unsigned char gc_snes_bytes[] = { 8, 0, 2, 3, 9, 1, 10, 11 };
+static const short gc_snes_btn[] = {
+       BTN_A, BTN_B, BTN_SELECT, BTN_START, BTN_X, BTN_Y, BTN_TL, BTN_TR
+};
 
 /*
  * gc_nes_read_packet() reads a NES/SNES packet.
@@ -244,40 +373,51 @@ static void gc_nes_read_packet(struct gc *gc, int length, unsigned char *data)
 static void gc_nes_process_packet(struct gc *gc)
 {
        unsigned char data[GC_SNESMOUSE_LENGTH];
+       struct gc_pad *pad;
        struct input_dev *dev;
        int i, j, s, len;
        char x_rel, y_rel;
 
-       len = gc->pads[GC_SNESMOUSE] ? GC_SNESMOUSE_LENGTH :
-                       (gc->pads[GC_SNES] ? GC_SNES_LENGTH : GC_NES_LENGTH);
+       len = gc->pad_count[GC_SNESMOUSE] ? GC_SNESMOUSE_LENGTH :
+                       (gc->pad_count[GC_SNES] ? GC_SNES_LENGTH : GC_NES_LENGTH);
 
        gc_nes_read_packet(gc, len, data);
 
        for (i = 0; i < GC_MAX_DEVICES; i++) {
 
+               pad = &gc->pads[i];
                dev = gc->dev[i];
-               if (!dev)
-                       continue;
-
                s = gc_status_bit[i];
 
-               if (s & (gc->pads[GC_NES] | gc->pads[GC_SNES])) {
+               switch (pad->type) {
+
+               case GC_NES:
+
                        input_report_abs(dev, ABS_X, !(s & data[6]) - !(s & data[7]));
                        input_report_abs(dev, ABS_Y, !(s & data[4]) - !(s & data[5]));
-               }
 
-               if (s & gc->pads[GC_NES])
                        for (j = 0; j < 4; j++)
-                               input_report_key(dev, gc_snes_btn[j], s & data[gc_nes_bytes[j]]);
+                               input_report_key(dev, gc_snes_btn[j],
+                                                s & data[gc_nes_bytes[j]]);
+                       input_sync(dev);
+                       break;
+
+               case GC_SNES:
+
+                       input_report_abs(dev, ABS_X, !(s & data[6]) - !(s & data[7]));
+                       input_report_abs(dev, ABS_Y, !(s & data[4]) - !(s & data[5]));
 
-               if (s & gc->pads[GC_SNES])
                        for (j = 0; j < 8; j++)
-                               input_report_key(dev, gc_snes_btn[j], s & data[gc_snes_bytes[j]]);
+                               input_report_key(dev, gc_snes_btn[j],
+                                                s & data[gc_snes_bytes[j]]);
+                       input_sync(dev);
+                       break;
 
-               if (s & gc->pads[GC_SNESMOUSE]) {
+               case GC_SNESMOUSE:
                        /*
-                        * The 4 unused bits from SNES controllers appear to be ID bits
-                        * so use them to make sure iwe are dealing with a mouse.
+                        * The 4 unused bits from SNES controllers appear
+                        * to be ID bits so use them to make sure we are
+                        * dealing with a mouse.
                         * gamepad is connected. This is important since
                         * my SNES gamepad sends 1's for bits 16-31, which
                         * cause the mouse pointer to quickly move to the
@@ -310,9 +450,14 @@ static void gc_nes_process_packet(struct gc *gc)
                                                y_rel = -y_rel;
                                        input_report_rel(dev, REL_Y, y_rel);
                                }
+
+                               input_sync(dev);
                        }
+                       break;
+
+               default:
+                       break;
                }
-               input_sync(dev);
        }
 }
 
@@ -340,29 +485,35 @@ static void gc_multi_read_packet(struct gc *gc, int length, unsigned char *data)
 static void gc_multi_process_packet(struct gc *gc)
 {
        unsigned char data[GC_MULTI2_LENGTH];
+       int data_len = gc->pad_count[GC_MULTI2] ? GC_MULTI2_LENGTH : GC_MULTI_LENGTH;
+       struct gc_pad *pad;
        struct input_dev *dev;
        int i, s;
 
-       gc_multi_read_packet(gc, gc->pads[GC_MULTI2] ? GC_MULTI2_LENGTH : GC_MULTI_LENGTH, data);
+       gc_multi_read_packet(gc, data_len, data);
 
        for (i = 0; i < GC_MAX_DEVICES; i++) {
-
-               dev = gc->dev[i];
-               if (!dev)
-                       continue;
-
+               pad = &gc->pads[i];
+               dev = pad->dev;
                s = gc_status_bit[i];
 
-               if (s & (gc->pads[GC_MULTI] | gc->pads[GC_MULTI2])) {
-                       input_report_abs(dev, ABS_X,  !(s & data[2]) - !(s & data[3]));
-                       input_report_abs(dev, ABS_Y,  !(s & data[0]) - !(s & data[1]));
-                       input_report_key(dev, BTN_TRIGGER, s & data[4]);
-               }
-
-               if (s & gc->pads[GC_MULTI2])
+               switch (pad->type) {
+               case GC_MULTI2:
                        input_report_key(dev, BTN_THUMB, s & data[5]);
+                       /* fall through */
 
-               input_sync(dev);
+               case GC_MULTI:
+                       input_report_abs(dev, ABS_X,
+                                        !(s & data[2]) - !(s & data[3]));
+                       input_report_abs(dev, ABS_Y,
+                                        !(s & data[0]) - !(s & data[1]));
+                       input_report_key(dev, BTN_TRIGGER, s & data[4]);
+                       input_sync(dev);
+                       break;
+
+               default:
+                       break;
+               }
        }
 }
 
@@ -398,30 +549,41 @@ static int gc_psx_delay = GC_PSX_DELAY;
 module_param_named(psx_delay, gc_psx_delay, uint, 0);
 MODULE_PARM_DESC(psx_delay, "Delay when accessing Sony PSX controller (usecs)");
 
-static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y };
-static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y,
-                               BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR };
-static short gc_psx_ddr_btn[] = { BTN_0, BTN_1, BTN_2, BTN_3 };
+static const short gc_psx_abs[] = {
+       ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y
+};
+static const short gc_psx_btn[] = {
+       BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y,
+       BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR
+};
+static const short gc_psx_ddr_btn[] = { BTN_0, BTN_1, BTN_2, BTN_3 };
 
 /*
  * gc_psx_command() writes 8bit command and reads 8bit data from
  * the psx pad.
  */
 
-static void gc_psx_command(struct gc *gc, int b, unsigned char data[GC_MAX_DEVICES])
+static void gc_psx_command(struct gc *gc, int b, unsigned char *data)
 {
+       struct parport *port = gc->pd->port;
        int i, j, cmd, read;
 
-       for (i = 0; i < GC_MAX_DEVICES; i++)
-               data[i] = 0;
+       memset(data, 0, GC_MAX_DEVICES);
 
        for (i = 0; i < GC_PSX_LENGTH; i++, b >>= 1) {
                cmd = (b & 1) ? GC_PSX_COMMAND : 0;
-               parport_write_data(gc->pd->port, cmd | GC_PSX_POWER);
+               parport_write_data(port, cmd | GC_PSX_POWER);
                udelay(gc_psx_delay);
-               read = parport_read_status(gc->pd->port) ^ 0x80;
-               for (j = 0; j < GC_MAX_DEVICES; j++)
-                       data[j] |= (read & gc_status_bit[j] & (gc->pads[GC_PSX] | gc->pads[GC_DDR])) ? (1 << i) : 0;
+
+               read = parport_read_status(port) ^ 0x80;
+
+               for (j = 0; j < GC_MAX_DEVICES; j++) {
+                       struct gc_pad *pad = &gc->pads[i];
+
+                       if (pad->type == GC_PSX || pad->type == GC_DDR)
+                               data[j] |= (read & gc_status_bit[j]) ? (1 << i) : 0;
+               }
+
                parport_write_data(gc->pd->port, cmd | GC_PSX_CLOCK | GC_PSX_POWER);
                udelay(gc_psx_delay);
        }
@@ -432,31 +594,40 @@ static void gc_psx_command(struct gc *gc, int b, unsigned char data[GC_MAX_DEVIC
  * device identifier code.
  */
 
-static void gc_psx_read_packet(struct gc *gc, unsigned char data[GC_MAX_DEVICES][GC_PSX_BYTES],
+static void gc_psx_read_packet(struct gc *gc,
+                              unsigned char data[GC_MAX_DEVICES][GC_PSX_BYTES],
                               unsigned char id[GC_MAX_DEVICES])
 {
        int i, j, max_len = 0;
        unsigned long flags;
        unsigned char data2[GC_MAX_DEVICES];
 
-       parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER);  /* Select pad */
+       /* Select pad */
+       parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER);
        udelay(gc_psx_delay);
-       parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_POWER);                  /* Deselect, begin command */
+       /* Deselect, begin command */
+       parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_POWER);
        udelay(gc_psx_delay);
 
        local_irq_save(flags);
 
-       gc_psx_command(gc, 0x01, data2);                                                /* Access pad */
-       gc_psx_command(gc, 0x42, id);                                                   /* Get device ids */
-       gc_psx_command(gc, 0, data2);                                                   /* Dump status */
+       gc_psx_command(gc, 0x01, data2);        /* Access pad */
+       gc_psx_command(gc, 0x42, id);           /* Get device ids */
+       gc_psx_command(gc, 0, data2);           /* Dump status */
+
+       /* Find the longest pad */
+       for (i = 0; i < GC_MAX_DEVICES; i++) {
+               struct gc_pad *pad = &gc->pads[i];
 
-       for (i =0; i < GC_MAX_DEVICES; i++)                                                             /* Find the longest pad */
-               if((gc_status_bit[i] & (gc->pads[GC_PSX] | gc->pads[GC_DDR]))
-                       && (GC_PSX_LEN(id[i]) > max_len)
-                       && (GC_PSX_LEN(id[i]) <= GC_PSX_BYTES))
+               if ((pad->type == GC_PSX || pad->type == GC_DDR) &&
+                   GC_PSX_LEN(id[i]) > max_len &&
+                   GC_PSX_LEN(id[i]) <= GC_PSX_BYTES) {
                        max_len = GC_PSX_LEN(id[i]);
+               }
+       }
 
-       for (i = 0; i < max_len; i++) {                                         /* Read in all the data */
+       /* Read in all the data */
+       for (i = 0; i < max_len; i++) {
                gc_psx_command(gc, 0, data2);
                for (j = 0; j < GC_MAX_DEVICES; j++)
                        data[j][i] = data2[j];
@@ -466,86 +637,104 @@ static void gc_psx_read_packet(struct gc *gc, unsigned char data[GC_MAX_DEVICES]
 
        parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER);
 
-       for(i = 0; i < GC_MAX_DEVICES; i++)                                                             /* Set id's to the real value */
+       /* Set id's to the real value */
+       for (i = 0; i < GC_MAX_DEVICES; i++)
                id[i] = GC_PSX_ID(id[i]);
 }
 
-static void gc_psx_process_packet(struct gc *gc)
+static void gc_psx_report_one(struct gc_pad *pad, unsigned char psx_type,
+                             unsigned char *data)
 {
-       unsigned char data[GC_MAX_DEVICES][GC_PSX_BYTES];
-       unsigned char id[GC_MAX_DEVICES];
-       struct input_dev *dev;
-       int i, j;
+       struct input_dev *dev = pad->dev;
+       int i;
 
-       gc_psx_read_packet(gc, data, id);
+       switch (psx_type) {
 
-       for (i = 0; i < GC_MAX_DEVICES; i++) {
+       case GC_PSX_RUMBLE:
 
-               dev = gc->dev[i];
-               if (!dev)
-                       continue;
+               input_report_key(dev, BTN_THUMBL, ~data[0] & 0x04);
+               input_report_key(dev, BTN_THUMBR, ~data[0] & 0x02);
 
-               switch (id[i]) {
+       case GC_PSX_NEGCON:
+       case GC_PSX_ANALOG:
 
-                       case GC_PSX_RUMBLE:
+               if (pad->type == GC_DDR) {
+                       for (i = 0; i < 4; i++)
+                               input_report_key(dev, gc_psx_ddr_btn[i],
+                                                ~data[0] & (0x10 << i));
+               } else {
+                       for (i = 0; i < 4; i++)
+                               input_report_abs(dev, gc_psx_abs[i + 2],
+                                                data[i + 2]);
 
-                               input_report_key(dev, BTN_THUMBL, ~data[i][0] & 0x04);
-                               input_report_key(dev, BTN_THUMBR, ~data[i][0] & 0x02);
+                       input_report_abs(dev, ABS_X,
+                               !!(data[0] & 0x80) * 128 + !(data[0] & 0x20) * 127);
+                       input_report_abs(dev, ABS_Y,
+                               !!(data[0] & 0x10) * 128 + !(data[0] & 0x40) * 127);
+               }
 
-                       case GC_PSX_NEGCON:
-                       case GC_PSX_ANALOG:
+               for (i = 0; i < 8; i++)
+                       input_report_key(dev, gc_psx_btn[i], ~data[1] & (1 << i));
 
-                               if (gc->pads[GC_DDR] & gc_status_bit[i]) {
-                                       for(j = 0; j < 4; j++)
-                                               input_report_key(dev, gc_psx_ddr_btn[j], ~data[i][0] & (0x10 << j));
-                               } else {
-                                       for (j = 0; j < 4; j++)
-                                               input_report_abs(dev, gc_psx_abs[j + 2], data[i][j + 2]);
+               input_report_key(dev, BTN_START,  ~data[0] & 0x08);
+               input_report_key(dev, BTN_SELECT, ~data[0] & 0x01);
 
-                                       input_report_abs(dev, ABS_X, 128 + !(data[i][0] & 0x20) * 127 - !(data[i][0] & 0x80) * 128);
-                                       input_report_abs(dev, ABS_Y, 128 + !(data[i][0] & 0x40) * 127 - !(data[i][0] & 0x10) * 128);
-                               }
+               input_sync(dev);
 
-                               for (j = 0; j < 8; j++)
-                                       input_report_key(dev, gc_psx_btn[j], ~data[i][1] & (1 << j));
+               break;
 
-                               input_report_key(dev, BTN_START,  ~data[i][0] & 0x08);
-                               input_report_key(dev, BTN_SELECT, ~data[i][0] & 0x01);
+       case GC_PSX_NORMAL:
 
-                               input_sync(dev);
+               if (pad->type == GC_DDR) {
+                       for (i = 0; i < 4; i++)
+                               input_report_key(dev, gc_psx_ddr_btn[i],
+                                                ~data[0] & (0x10 << i));
+               } else {
+                       input_report_abs(dev, ABS_X,
+                               !!(data[0] & 0x80) * 128 + !(data[0] & 0x20) * 127);
+                       input_report_abs(dev, ABS_Y,
+                               !!(data[0] & 0x10) * 128 + !(data[0] & 0x40) * 127);
 
-                               break;
-
-                       case GC_PSX_NORMAL:
-                               if (gc->pads[GC_DDR] & gc_status_bit[i]) {
-                                       for(j = 0; j < 4; j++)
-                                               input_report_key(dev, gc_psx_ddr_btn[j], ~data[i][0] & (0x10 << j));
-                               } else {
-                                       input_report_abs(dev, ABS_X, 128 + !(data[i][0] & 0x20) * 127 - !(data[i][0] & 0x80) * 128);
-                                       input_report_abs(dev, ABS_Y, 128 + !(data[i][0] & 0x40) * 127 - !(data[i][0] & 0x10) * 128);
-
-                                       /* for some reason if the extra axes are left unset they drift */
-                                       /* for (j = 0; j < 4; j++)
-                                               input_report_abs(dev, gc_psx_abs[j + 2], 128);
-                                        * This needs to be debugged properly,
-                                        * maybe fuzz processing needs to be done in input_sync()
-                                        *                               --vojtech
-                                        */
-                               }
+                       /*
+                        * For some reason if the extra axes are left unset
+                        * they drift.
+                        * for (i = 0; i < 4; i++)
+                               input_report_abs(dev, gc_psx_abs[i + 2], 128);
+                        * This needs to be debugged properly,
+                        * maybe fuzz processing needs to be done
+                        * in input_sync()
+                        *                               --vojtech
+                        */
+               }
 
-                               for (j = 0; j < 8; j++)
-                                       input_report_key(dev, gc_psx_btn[j], ~data[i][1] & (1 << j));
+               for (i = 0; i < 8; i++)
+                       input_report_key(dev, gc_psx_btn[i], ~data[1] & (1 << i));
 
-                               input_report_key(dev, BTN_START,  ~data[i][0] & 0x08);
-                               input_report_key(dev, BTN_SELECT, ~data[i][0] & 0x01);
+               input_report_key(dev, BTN_START,  ~data[0] & 0x08);
+               input_report_key(dev, BTN_SELECT, ~data[0] & 0x01);
 
-                               input_sync(dev);
+               input_sync(dev);
 
-                               break;
+               break;
 
-                       case 0: /* not a pad, ignore */
-                               break;
-               }
+       default: /* not a pad, ignore */
+               break;
+       }
+}
+
+static void gc_psx_process_packet(struct gc *gc)
+{
+       unsigned char data[GC_MAX_DEVICES][GC_PSX_BYTES];
+       unsigned char id[GC_MAX_DEVICES];
+       struct gc_pad *pad;
+       int i;
+
+       gc_psx_read_packet(gc, data, id);
+
+       for (i = 0; i < GC_MAX_DEVICES; i++) {
+               pad = &gc->pads[i];
+               if (pad->type == GC_PSX || pad->type == GC_DDR)
+                       gc_psx_report_one(pad, id[i], data[i]);
        }
 }
 
@@ -561,28 +750,31 @@ static void gc_timer(unsigned long private)
  * N64 pads - must be read first, any read confuses them for 200 us
  */
 
-       if (gc->pads[GC_N64])
+       if (gc->pad_count[GC_N64])
                gc_n64_process_packet(gc);
 
 /*
  * NES and SNES pads or mouse
  */
 
-       if (gc->pads[GC_NES] || gc->pads[GC_SNES] || gc->pads[GC_SNESMOUSE])
+       if (gc->pad_count[GC_NES] ||
+           gc->pad_count[GC_SNES] ||
+           gc->pad_count[GC_SNESMOUSE]) {
                gc_nes_process_packet(gc);
+       }
 
 /*
  * Multi and Multi2 joysticks
  */
 
-       if (gc->pads[GC_MULTI] || gc->pads[GC_MULTI2])
+       if (gc->pad_count[GC_MULTI] || gc->pad_count[GC_MULTI2])
                gc_multi_process_packet(gc);
 
 /*
  * PSX controllers
  */
 
-       if (gc->pads[GC_PSX] || gc->pads[GC_DDR])
+       if (gc->pad_count[GC_PSX] || gc->pad_count[GC_DDR])
                gc_psx_process_packet(gc);
 
        mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
@@ -622,25 +814,29 @@ static void gc_close(struct input_dev *dev)
 
 static int __init gc_setup_pad(struct gc *gc, int idx, int pad_type)
 {
+       struct gc_pad *pad = &gc->pads[idx];
        struct input_dev *input_dev;
        int i;
-
-       if (!pad_type)
-               return 0;
+       int err;
 
        if (pad_type < 1 || pad_type > GC_MAX) {
-               printk(KERN_WARNING "gamecon.c: Pad type %d unknown\n", pad_type);
+               pr_err("Pad type %d unknown\n", pad_type);
                return -EINVAL;
        }
 
-       gc->dev[idx] = input_dev = input_allocate_device();
+       pad->dev = input_dev = input_allocate_device();
        if (!input_dev) {
-               printk(KERN_ERR "gamecon.c: Not enough memory for input device\n");
+               pr_err("Not enough memory for input device\n");
                return -ENOMEM;
        }
 
+       pad->type = pad_type;
+
+       snprintf(pad->phys, sizeof(pad->phys),
+                "%s/input%d", gc->pd->port->name, idx);
+
        input_dev->name = gc_names[pad_type];
-       input_dev->phys = gc->phys[idx];
+       input_dev->phys = pad->phys;
        input_dev->id.bustype = BUS_PARPORT;
        input_dev->id.vendor = 0x0001;
        input_dev->id.product = pad_type;
@@ -659,61 +855,76 @@ static int __init gc_setup_pad(struct gc *gc, int idx, int pad_type)
        } else
                input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
 
-       gc->pads[0] |= gc_status_bit[idx];
-       gc->pads[pad_type] |= gc_status_bit[idx];
+       gc->pad_count[pad_type]++;
 
        switch (pad_type) {
 
-               case GC_N64:
-                       for (i = 0; i < 10; i++)
-                               set_bit(gc_n64_btn[i], input_dev->keybit);
-
-                       for (i = 0; i < 2; i++) {
-                               input_set_abs_params(input_dev, ABS_X + i, -127, 126, 0, 2);
-                               input_set_abs_params(input_dev, ABS_HAT0X + i, -1, 1, 0, 0);
-                       }
-
-                       break;
-
-               case GC_SNESMOUSE:
-                       set_bit(BTN_LEFT, input_dev->keybit);
-                       set_bit(BTN_RIGHT, input_dev->keybit);
-                       set_bit(REL_X, input_dev->relbit);
-                       set_bit(REL_Y, input_dev->relbit);
-                       break;
-
-               case GC_SNES:
-                       for (i = 4; i < 8; i++)
-                               set_bit(gc_snes_btn[i], input_dev->keybit);
-               case GC_NES:
-                       for (i = 0; i < 4; i++)
-                               set_bit(gc_snes_btn[i], input_dev->keybit);
-                       break;
-
-               case GC_MULTI2:
-                       set_bit(BTN_THUMB, input_dev->keybit);
-               case GC_MULTI:
-                       set_bit(BTN_TRIGGER, input_dev->keybit);
-                       break;
-
-               case GC_PSX:
-                       for (i = 0; i < 6; i++)
-                               input_set_abs_params(input_dev, gc_psx_abs[i], 4, 252, 0, 2);
-                       for (i = 0; i < 12; i++)
-                               set_bit(gc_psx_btn[i], input_dev->keybit);
+       case GC_N64:
+               for (i = 0; i < 10; i++)
+                       __set_bit(gc_n64_btn[i], input_dev->keybit);
 
-                       break;
+               for (i = 0; i < 2; i++) {
+                       input_set_abs_params(input_dev, ABS_X + i, -127, 126, 0, 2);
+                       input_set_abs_params(input_dev, ABS_HAT0X + i, -1, 1, 0, 0);
+               }
 
-               case GC_DDR:
-                       for (i = 0; i < 4; i++)
-                               set_bit(gc_psx_ddr_btn[i], input_dev->keybit);
-                       for (i = 0; i < 12; i++)
-                               set_bit(gc_psx_btn[i], input_dev->keybit);
+               err = gc_n64_init_ff(input_dev, idx);
+               if (err) {
+                       pr_warning("Failed to initiate rumble for N64 device %d\n", idx);
+                       goto err_free_dev;
+               }
 
-                       break;
+               break;
+
+       case GC_SNESMOUSE:
+               __set_bit(BTN_LEFT, input_dev->keybit);
+               __set_bit(BTN_RIGHT, input_dev->keybit);
+               __set_bit(REL_X, input_dev->relbit);
+               __set_bit(REL_Y, input_dev->relbit);
+               break;
+
+       case GC_SNES:
+               for (i = 4; i < 8; i++)
+                       __set_bit(gc_snes_btn[i], input_dev->keybit);
+       case GC_NES:
+               for (i = 0; i < 4; i++)
+                       __set_bit(gc_snes_btn[i], input_dev->keybit);
+               break;
+
+       case GC_MULTI2:
+               __set_bit(BTN_THUMB, input_dev->keybit);
+       case GC_MULTI:
+               __set_bit(BTN_TRIGGER, input_dev->keybit);
+               break;
+
+       case GC_PSX:
+               for (i = 0; i < 6; i++)
+                       input_set_abs_params(input_dev,
+                                            gc_psx_abs[i], 4, 252, 0, 2);
+               for (i = 0; i < 12; i++)
+                       __set_bit(gc_psx_btn[i], input_dev->keybit);
+
+               break;
+
+       case GC_DDR:
+               for (i = 0; i < 4; i++)
+                       __set_bit(gc_psx_ddr_btn[i], input_dev->keybit);
+               for (i = 0; i < 12; i++)
+                       __set_bit(gc_psx_btn[i], input_dev->keybit);
+
+               break;
        }
 
+       err = input_register_device(pad->dev);
+       if (err)
+               goto err_free_dev;
+
        return 0;
+
+err_free_dev:
+       input_free_device(pad->dev);
+       pad->dev = NULL;
+       return err;
 }
 
 static struct gc __init *gc_probe(int parport, int *pads, int n_pads)
@@ -722,52 +933,47 @@ static struct gc __init *gc_probe(int parport, int *pads, int n_pads)
        struct parport *pp;
        struct pardevice *pd;
        int i;
+       int count = 0;
        int err;
 
        pp = parport_find_number(parport);
        if (!pp) {
-               printk(KERN_ERR "gamecon.c: no such parport\n");
+               pr_err("no such parport %d\n", parport);
                err = -EINVAL;
                goto err_out;
        }
 
        pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
        if (!pd) {
-               printk(KERN_ERR "gamecon.c: parport busy already - lp.o loaded?\n");
+               pr_err("parport busy already - lp.o loaded?\n");
                err = -EBUSY;
                goto err_put_pp;
        }
 
        gc = kzalloc(sizeof(struct gc), GFP_KERNEL);
        if (!gc) {
-               printk(KERN_ERR "gamecon.c: Not enough memory\n");
+               pr_err("Not enough memory\n");
                err = -ENOMEM;
                goto err_unreg_pardev;
        }
 
        mutex_init(&gc->mutex);
        gc->pd = pd;
-       init_timer(&gc->timer);
-       gc->timer.data = (long) gc;
-       gc->timer.function = gc_timer;
+       setup_timer(&gc->timer, gc_timer, (long) gc);
 
        for (i = 0; i < n_pads && i < GC_MAX_DEVICES; i++) {
                if (!pads[i])
                        continue;
 
-               snprintf(gc->phys[i], sizeof(gc->phys[i]),
-                        "%s/input%d", gc->pd->port->name, i);
                err = gc_setup_pad(gc, i, pads[i]);
                if (err)
                        goto err_unreg_devs;
 
-               err = input_register_device(gc->dev[i]);
-               if (err)
-                       goto err_free_dev;
+               count++;
        }
 
-       if (!gc->pads[0]) {
-               printk(KERN_ERR "gamecon.c: No valid devices specified\n");
+       if (count == 0) {
+               pr_err("No valid devices specified\n");
                err = -EINVAL;
                goto err_free_gc;
        }
@@ -775,12 +981,10 @@ static struct gc __init *gc_probe(int parport, int *pads, int n_pads)
        parport_put_port(pp);
        return gc;
 
- err_free_dev:
-       input_free_device(gc->dev[i]);
  err_unreg_devs:
        while (--i >= 0)
-               if (gc->dev[i])
-                       input_unregister_device(gc->dev[i]);
+               if (gc->pads[i].dev)
+                       input_unregister_device(gc->pads[i].dev);
  err_free_gc:
        kfree(gc);
  err_unreg_pardev:
@@ -796,8 +1000,8 @@ static void gc_remove(struct gc *gc)
        int i;
 
        for (i = 0; i < GC_MAX_DEVICES; i++)
-               if (gc->dev[i])
-                       input_unregister_device(gc->dev[i]);
+               if (gc->pads[i].dev)
+                       input_unregister_device(gc->pads[i].dev);
        parport_unregister_device(gc->pd);
        kfree(gc);
 }
@@ -813,7 +1017,7 @@ static int __init gc_init(void)
                        continue;
 
                if (gc_cfg[i].nargs < 2) {
-                       printk(KERN_ERR "gamecon.c: at least one device must be specified\n");
+                       pr_err("at least one device must be specified\n");
                        err = -EINVAL;
                        break;
                }
index 8a28fb7846dc1f16a18a064b6cc631d2ca82afa4..9b3353b404da9180cdfcc8e7bfcda7ab74ade553 100644 (file)
@@ -86,9 +86,8 @@
 
 /* xbox d-pads should map to buttons, as is required for DDR pads
    but we map them to axes when possible to simplify things */
-#define MAP_DPAD_TO_BUTTONS    0
-#define MAP_DPAD_TO_AXES       1
-#define MAP_DPAD_UNKNOWN       2
+#define MAP_DPAD_TO_BUTTONS            (1 << 0)
+#define MAP_TRIGGERS_TO_BUTTONS                (1 << 1)
 
 #define XTYPE_XBOX        0
 #define XTYPE_XBOX360     1
@@ -99,57 +98,61 @@ static int dpad_to_buttons;
 module_param(dpad_to_buttons, bool, S_IRUGO);
 MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads");
 
+static int triggers_to_buttons;
+module_param(triggers_to_buttons, bool, S_IRUGO);
+MODULE_PARM_DESC(triggers_to_buttons, "Map triggers to buttons rather than axes for unknown pads");
+
 static const struct xpad_device {
        u16 idVendor;
        u16 idProduct;
        char *name;
-       u8 dpad_mapping;
+       u8 mapping;
        u8 xtype;
 } xpad_device[] = {
-       { 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x045e, 0x0287, "Microsoft Xbox Controller S", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", 0, XTYPE_XBOX },
+       { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", 0, XTYPE_XBOX },
+       { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", 0, XTYPE_XBOX },
+       { 0x045e, 0x0287, "Microsoft Xbox Controller S", 0, XTYPE_XBOX },
        { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
        { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
-       { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x046d, 0xc242, "Logitech Chillstream Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
-       { 0x046d, 0xca84, "Logitech Xbox Cordless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x046d, 0xca88, "Logitech Compact Controller for Xbox", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x05fd, 0x1007, "Mad Catz Controller (unverified)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0738, 0x4516, "Mad Catz Control Pad", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0738, 0x4522, "Mad Catz LumiCON", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0738, 0x4526, "Mad Catz Control Pad Pro", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0738, 0x4536, "Mad Catz MicroCON", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
+       { 0x046d, 0xc242, "Logitech Chillstream Controller", 0, XTYPE_XBOX360 },
+       { 0x046d, 0xca84, "Logitech Xbox Cordless Controller", 0, XTYPE_XBOX },
+       { 0x046d, 0xca88, "Logitech Compact Controller for Xbox", 0, XTYPE_XBOX },
+       { 0x05fd, 0x1007, "Mad Catz Controller (unverified)", 0, XTYPE_XBOX },
+       { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", 0, XTYPE_XBOX },
+       { 0x0738, 0x4516, "Mad Catz Control Pad", 0, XTYPE_XBOX },
+       { 0x0738, 0x4522, "Mad Catz LumiCON", 0, XTYPE_XBOX },
+       { 0x0738, 0x4526, "Mad Catz Control Pad Pro", 0, XTYPE_XBOX },
+       { 0x0738, 0x4536, "Mad Catz MicroCON", 0, XTYPE_XBOX },
        { 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
-       { 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
-       { 0x0738, 0x4738, "Mad Catz Wired Xbox 360 Controller (SFIV)", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
+       { 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", 0, XTYPE_XBOX },
+       { 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller", 0, XTYPE_XBOX360 },
+       { 0x0738, 0x4738, "Mad Catz Wired Xbox 360 Controller (SFIV)", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
        { 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
-       { 0x0c12, 0x8802, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0c12, 0x880a, "Pelican Eclipse PL-2023", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0c12, 0x8810, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0e4c, 0x1097, "Radica Gamester Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0e4c, 0x2390, "Radica Games Jtech Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0e6f, 0x0005, "Eclipse wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0e6f, 0x0006, "Edge wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0e6f, 0x0006, "Pelican 'TSZ' Wired Xbox 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
-       { 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0f30, 0x0202, "Joytech Advanced Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x0c12, 0x8802, "Zeroplus Xbox Controller", 0, XTYPE_XBOX },
+       { 0x0c12, 0x880a, "Pelican Eclipse PL-2023", 0, XTYPE_XBOX },
+       { 0x0c12, 0x8810, "Zeroplus Xbox Controller", 0, XTYPE_XBOX },
+       { 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", 0, XTYPE_XBOX },
+       { 0x0e4c, 0x1097, "Radica Gamester Controller", 0, XTYPE_XBOX },
+       { 0x0e4c, 0x2390, "Radica Games Jtech Controller", 0, XTYPE_XBOX },
+       { 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", 0, XTYPE_XBOX },
+       { 0x0e6f, 0x0005, "Eclipse wireless Controller", 0, XTYPE_XBOX },
+       { 0x0e6f, 0x0006, "Edge wireless Controller", 0, XTYPE_XBOX },
+       { 0x0e6f, 0x0006, "Pelican 'TSZ' Wired Xbox 360 Controller", 0, XTYPE_XBOX360 },
+       { 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", 0, XTYPE_XBOX },
+       { 0x0f30, 0x0202, "Joytech Advanced Controller", 0, XTYPE_XBOX },
+       { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX },
+       { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", 0, XTYPE_XBOX },
        { 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
-       { 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
+       { 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", 0, XTYPE_XBOX360 },
        { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
-       { 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
-       { 0x045e, 0x028e, "Microsoft X-Box 360 pad", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
+       { 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", 0, XTYPE_XBOX360 },
+       { 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 },
        { 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
-       { 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
-       { 0xffff, 0xffff, "Chinese-made Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN, XTYPE_UNKNOWN }
+       { 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+       { 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX },
+       { 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN }
 };
 
 /* buttons shared with xbox and xbox360 */
@@ -165,13 +168,20 @@ static const signed short xpad_btn[] = {
        -1                      /* terminating entry */
 };
 
-/* only used if MAP_DPAD_TO_BUTTONS */
+/* used when dpad is mapped to nuttons */
 static const signed short xpad_btn_pad[] = {
        BTN_LEFT, BTN_RIGHT,            /* d-pad left, right */
        BTN_0, BTN_1,                   /* d-pad up, down (XXX names??) */
        -1                              /* terminating entry */
 };
 
+/* used when triggers are mapped to buttons */
+static const signed short xpad_btn_triggers[] = {
+       BTN_TL2, BTN_TR2,               /* triggers left/right */
+       -1
+};
+
+
 static const signed short xpad360_btn[] = {  /* buttons for x360 controller */
        BTN_TL, BTN_TR,         /* Button LB/RB */
        BTN_MODE,               /* The big X button */
@@ -181,16 +191,21 @@ static const signed short xpad360_btn[] = {  /* buttons for x360 controller */
 static const signed short xpad_abs[] = {
        ABS_X, ABS_Y,           /* left stick */
        ABS_RX, ABS_RY,         /* right stick */
-       ABS_Z, ABS_RZ,          /* triggers left/right */
        -1                      /* terminating entry */
 };
 
-/* only used if MAP_DPAD_TO_AXES */
+/* used when dpad is mapped to axes */
 static const signed short xpad_abs_pad[] = {
        ABS_HAT0X, ABS_HAT0Y,   /* d-pad axes */
        -1                      /* terminating entry */
 };
 
+/* used when triggers are mapped to axes */
+static const signed short xpad_abs_triggers[] = {
+       ABS_Z, ABS_RZ,          /* triggers left/right */
+       -1
+};
+
 /* Xbox 360 has a vendor-specific class, so we cannot match it with only
  * USB_INTERFACE_INFO (also specifically refused by USB subsystem), so we
  * match against vendor id as well. Wired Xbox 360 devices have protocol 1,
@@ -246,7 +261,7 @@ struct usb_xpad {
 
        char phys[64];                  /* physical device path */
 
-       int dpad_mapping;               /* map d-pad to buttons or to axes */
+       int mapping;                    /* map d-pad to buttons or to axes */
        int xtype;                      /* type of xbox device */
 };
 
@@ -277,20 +292,25 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
                         ~(__s16) le16_to_cpup((__le16 *)(data + 18)));
 
        /* triggers left/right */
-       input_report_abs(dev, ABS_Z, data[10]);
-       input_report_abs(dev, ABS_RZ, data[11]);
+       if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
+               input_report_key(dev, BTN_TL2, data[10]);
+               input_report_key(dev, BTN_TR2, data[11]);
+       } else {
+               input_report_abs(dev, ABS_Z, data[10]);
+               input_report_abs(dev, ABS_RZ, data[11]);
+       }
 
        /* digital pad */
-       if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) {
-               input_report_abs(dev, ABS_HAT0X,
-                                !!(data[2] & 0x08) - !!(data[2] & 0x04));
-               input_report_abs(dev, ABS_HAT0Y,
-                                !!(data[2] & 0x02) - !!(data[2] & 0x01));
-       } else /* xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS */ {
+       if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
                input_report_key(dev, BTN_LEFT,  data[2] & 0x04);
                input_report_key(dev, BTN_RIGHT, data[2] & 0x08);
                input_report_key(dev, BTN_0,     data[2] & 0x01); /* up */
                input_report_key(dev, BTN_1,     data[2] & 0x02); /* down */
+       } else {
+               input_report_abs(dev, ABS_HAT0X,
+                                !!(data[2] & 0x08) - !!(data[2] & 0x04));
+               input_report_abs(dev, ABS_HAT0Y,
+                                !!(data[2] & 0x02) - !!(data[2] & 0x01));
        }
 
        /* start/back buttons and stick press left/right */
@@ -328,17 +348,17 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
        struct input_dev *dev = xpad->dev;
 
        /* digital pad */
-       if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) {
-               input_report_abs(dev, ABS_HAT0X,
-                                !!(data[2] & 0x08) - !!(data[2] & 0x04));
-               input_report_abs(dev, ABS_HAT0Y,
-                                !!(data[2] & 0x02) - !!(data[2] & 0x01));
-       } else if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS) {
+       if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
                /* dpad as buttons (right, left, down, up) */
                input_report_key(dev, BTN_LEFT, data[2] & 0x04);
                input_report_key(dev, BTN_RIGHT, data[2] & 0x08);
                input_report_key(dev, BTN_0, data[2] & 0x01);   /* up */
                input_report_key(dev, BTN_1, data[2] & 0x02);   /* down */
+       } else {
+               input_report_abs(dev, ABS_HAT0X,
+                                !!(data[2] & 0x08) - !!(data[2] & 0x04));
+               input_report_abs(dev, ABS_HAT0Y,
+                                !!(data[2] & 0x02) - !!(data[2] & 0x01));
        }
 
        /* start/back buttons */
@@ -371,8 +391,13 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
                         ~(__s16) le16_to_cpup((__le16 *)(data + 12)));
 
        /* triggers left/right */
-       input_report_abs(dev, ABS_Z, data[4]);
-       input_report_abs(dev, ABS_RZ, data[5]);
+       if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
+               input_report_key(dev, BTN_TL2, data[4]);
+               input_report_key(dev, BTN_TR2, data[5]);
+       } else {
+               input_report_abs(dev, ABS_Z, data[4]);
+               input_report_abs(dev, ABS_RZ, data[5]);
+       }
 
        input_sync(dev);
 }
@@ -505,7 +530,7 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
        struct usb_endpoint_descriptor *ep_irq_out;
        int error = -ENOMEM;
 
-       if (xpad->xtype != XTYPE_XBOX360)
+       if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype != XTYPE_XBOX)
                return 0;
 
        xpad->odata = usb_buffer_alloc(xpad->udev, XPAD_PKT_LEN,
@@ -535,13 +560,13 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
 
 static void xpad_stop_output(struct usb_xpad *xpad)
 {
-       if (xpad->xtype == XTYPE_XBOX360)
+       if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX)
                usb_kill_urb(xpad->irq_out);
 }
 
 static void xpad_deinit_output(struct usb_xpad *xpad)
 {
-       if (xpad->xtype == XTYPE_XBOX360) {
+       if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX) {
                usb_free_urb(xpad->irq_out);
                usb_buffer_free(xpad->udev, XPAD_PKT_LEN,
                                xpad->odata, xpad->odata_dma);
@@ -554,24 +579,45 @@ static void xpad_stop_output(struct usb_xpad *xpad) {}
 #endif
 
 #ifdef CONFIG_JOYSTICK_XPAD_FF
-static int xpad_play_effect(struct input_dev *dev, void *data,
-                           struct ff_effect *effect)
+static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect)
 {
        struct usb_xpad *xpad = input_get_drvdata(dev);
 
        if (effect->type == FF_RUMBLE) {
                __u16 strong = effect->u.rumble.strong_magnitude;
                __u16 weak = effect->u.rumble.weak_magnitude;
-               xpad->odata[0] = 0x00;
-               xpad->odata[1] = 0x08;
-               xpad->odata[2] = 0x00;
-               xpad->odata[3] = strong / 256;
-               xpad->odata[4] = weak / 256;
-               xpad->odata[5] = 0x00;
-               xpad->odata[6] = 0x00;
-               xpad->odata[7] = 0x00;
-               xpad->irq_out->transfer_buffer_length = 8;
-               usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
+
+               switch (xpad->xtype) {
+
+               case XTYPE_XBOX:
+                       xpad->odata[0] = 0x00;
+                       xpad->odata[1] = 0x06;
+                       xpad->odata[2] = 0x00;
+                       xpad->odata[3] = strong / 256;  /* left actuator */
+                       xpad->odata[4] = 0x00;
+                       xpad->odata[5] = weak / 256;    /* right actuator */
+                       xpad->irq_out->transfer_buffer_length = 6;
+
+                       return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
+
+               case XTYPE_XBOX360:
+                       xpad->odata[0] = 0x00;
+                       xpad->odata[1] = 0x08;
+                       xpad->odata[2] = 0x00;
+                       xpad->odata[3] = strong / 256;  /* left actuator? */
+                       xpad->odata[4] = weak / 256;    /* right actuator? */
+                       xpad->odata[5] = 0x00;
+                       xpad->odata[6] = 0x00;
+                       xpad->odata[7] = 0x00;
+                       xpad->irq_out->transfer_buffer_length = 8;
+
+                       return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
+
+               default:
+                       dbg("%s - rumble command sent to unsupported xpad type: %d",
+                               __func__, xpad->xtype);
+                       return -1;
+               }
        }
 
        return 0;
@@ -579,7 +625,7 @@ static int xpad_play_effect(struct input_dev *dev, void *data,
 
 static int xpad_init_ff(struct usb_xpad *xpad)
 {
-       if (xpad->xtype != XTYPE_XBOX360)
+       if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype != XTYPE_XBOX)
                return 0;
 
        input_set_capability(xpad->dev, EV_FF, FF_RUMBLE);
@@ -712,11 +758,11 @@ static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
                input_set_abs_params(input_dev, abs, -32768, 32767, 16, 128);
                break;
        case ABS_Z:
-       case ABS_RZ:    /* the triggers */
+       case ABS_RZ:    /* the triggers (if mapped to axes) */
                input_set_abs_params(input_dev, abs, 0, 255, 0, 0);
                break;
        case ABS_HAT0X:
-       case ABS_HAT0Y: /* the d-pad (only if MAP_DPAD_TO_AXES) */
+       case ABS_HAT0Y: /* the d-pad (only if dpad is mapped to axes */
                input_set_abs_params(input_dev, abs, -1, 1, 0, 0);
                break;
        }
@@ -752,10 +798,9 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
                goto fail2;
 
        xpad->udev = udev;
-       xpad->dpad_mapping = xpad_device[i].dpad_mapping;
+       xpad->mapping = xpad_device[i].mapping;
        xpad->xtype = xpad_device[i].xtype;
-       if (xpad->dpad_mapping == MAP_DPAD_UNKNOWN)
-               xpad->dpad_mapping = !dpad_to_buttons;
+
        if (xpad->xtype == XTYPE_UNKNOWN) {
                if (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC) {
                        if (intf->cur_altsetting->desc.bInterfaceProtocol == 129)
@@ -764,7 +809,13 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
                                xpad->xtype = XTYPE_XBOX360;
                } else
                        xpad->xtype = XTYPE_XBOX;
+
+               if (dpad_to_buttons)
+                       xpad->mapping |= MAP_DPAD_TO_BUTTONS;
+               if (triggers_to_buttons)
+                       xpad->mapping |= MAP_TRIGGERS_TO_BUTTONS;
        }
+
        xpad->dev = input_dev;
        usb_make_path(udev, xpad->phys, sizeof(xpad->phys));
        strlcat(xpad->phys, "/input0", sizeof(xpad->phys));
@@ -781,25 +832,37 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
 
        input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
 
-       /* set up buttons */
+       /* set up standard buttons and axes */
        for (i = 0; xpad_common_btn[i] >= 0; i++)
-               set_bit(xpad_common_btn[i], input_dev->keybit);
-       if ((xpad->xtype == XTYPE_XBOX360) || (xpad->xtype == XTYPE_XBOX360W))
-               for (i = 0; xpad360_btn[i] >= 0; i++)
-                       set_bit(xpad360_btn[i], input_dev->keybit);
-       else
-               for (i = 0; xpad_btn[i] >= 0; i++)
-                       set_bit(xpad_btn[i], input_dev->keybit);
-       if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS)
-               for (i = 0; xpad_btn_pad[i] >= 0; i++)
-                       set_bit(xpad_btn_pad[i], input_dev->keybit);
+               __set_bit(xpad_common_btn[i], input_dev->keybit);
 
-       /* set up axes */
        for (i = 0; xpad_abs[i] >= 0; i++)
                xpad_set_up_abs(input_dev, xpad_abs[i]);
-       if (xpad->dpad_mapping == MAP_DPAD_TO_AXES)
+
+       /* Now set up model-specific ones */
+       if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W) {
+               for (i = 0; xpad360_btn[i] >= 0; i++)
+                       __set_bit(xpad360_btn[i], input_dev->keybit);
+       } else {
+               for (i = 0; xpad_btn[i] >= 0; i++)
+                       __set_bit(xpad_btn[i], input_dev->keybit);
+       }
+
+       if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
+               for (i = 0; xpad_btn_pad[i] >= 0; i++)
+                       __set_bit(xpad_btn_pad[i], input_dev->keybit);
+       } else {
                for (i = 0; xpad_abs_pad[i] >= 0; i++)
                    xpad_set_up_abs(input_dev, xpad_abs_pad[i]);
+       }
+
+       if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
+               for (i = 0; xpad_btn_triggers[i] >= 0; i++)
+                       __set_bit(xpad_btn_triggers[i], input_dev->keybit);
+       } else {
+               for (i = 0; xpad_abs_triggers[i] >= 0; i++)
+                       xpad_set_up_abs(input_dev, xpad_abs_triggers[i]);
+       }
 
        error = xpad_init_output(intf, xpad);
        if (error)
index 02c836e11813601471de72653381584bdca9684a..64c102355f532198829b7c381ddf75376a132a8a 100644 (file)
@@ -35,10 +35,10 @@ config KEYBOARD_ADP5520
          be called adp5520-keys.
 
 config KEYBOARD_ADP5588
-       tristate "ADP5588 I2C QWERTY Keypad and IO Expander"
+       tristate "ADP5588/87 I2C QWERTY Keypad and IO Expander"
        depends on I2C
        help
-         Say Y here if you want to use a ADP5588 attached to your
+         Say Y here if you want to use a ADP5588/87 attached to your
          system I2C bus.
 
          To compile this driver as a module, choose M here: the
@@ -144,13 +144,15 @@ config KEYBOARD_BFIN
          module will be called bf54x-keys.
 
 config KEYBOARD_CORGI
-       tristate "Corgi keyboard"
+       tristate "Corgi keyboard (deprecated)"
        depends on PXA_SHARPSL
-       default y
        help
          Say Y here to enable the keyboard on the Sharp Zaurus SL-C7xx
          series of PDAs.
 
+         This driver is now deprecated, use generic GPIO based matrix
+         keyboard driver instead.
+
          To compile this driver as a module, choose M here: the
          module will be called corgikbd.
 
@@ -292,6 +294,15 @@ config KEYBOARD_MAX7359
          To compile this driver as a module, choose M here: the
          module will be called max7359_keypad.
 
+config KEYBOARD_IMX
+       tristate "IMX keypad support"
+       depends on ARCH_MXC
+       help
+         Enable support for IMX keypad port.
+
+         To compile this driver as a module, choose M here: the
+         module will be called imx_keypad.
+
 config KEYBOARD_NEWTON
        tristate "Newton keyboard"
        select SERIO
@@ -329,13 +340,15 @@ config KEYBOARD_PXA930_ROTARY
          module will be called pxa930_rotary.
 
 config KEYBOARD_SPITZ
-       tristate "Spitz keyboard"
+       tristate "Spitz keyboard (deprecated)"
        depends on PXA_SHARPSL
-       default y
        help
          Say Y here to enable the keyboard on the Sharp Zaurus SL-C1000,
          SL-C3000 and Sl-C3100 series of PDAs.
 
+         This driver is now deprecated, use generic GPIO based matrix
+         keyboard driver instead.
+
          To compile this driver as a module, choose M here: the
          module will be called spitzkbd.
 
@@ -363,7 +376,7 @@ config KEYBOARD_SUNKBD
 
 config KEYBOARD_SH_KEYSC
        tristate "SuperH KEYSC keypad support"
-       depends on SUPERH
+       depends on SUPERH || ARCH_SHMOBILE
        help
          Say Y here if you want to use a keypad attached to the KEYSC block
          on SuperH processors such as sh7722 and sh7343.
@@ -402,12 +415,14 @@ config KEYBOARD_TWL4030
          module will be called twl4030_keypad.
 
 config KEYBOARD_TOSA
-       tristate "Tosa keyboard"
+       tristate "Tosa keyboard (deprecated)"
        depends on MACH_TOSA
-       default y
        help
          Say Y here to enable the keyboard on the Sharp Zaurus SL-6000x (Tosa)
 
+         This driver is now deprecated, use generic GPIO based matrix
+         keyboard driver instead.
+
          To compile this driver as a module, choose M here: the
          module will be called tosakbd.
 
index 78654ef6520644c98710b6ff640acd37bc8c224d..706c6b5ed5f44a7f9c95973503c073a3081e97b4 100644 (file)
@@ -17,6 +17,7 @@ obj-$(CONFIG_KEYBOARD_EP93XX)         += ep93xx_keypad.o
 obj-$(CONFIG_KEYBOARD_GPIO)            += gpio_keys.o
 obj-$(CONFIG_KEYBOARD_HIL)             += hil_kbd.o
 obj-$(CONFIG_KEYBOARD_HIL_OLD)         += hilkbd.o
+obj-$(CONFIG_KEYBOARD_IMX)             += imx_keypad.o
 obj-$(CONFIG_KEYBOARD_HP6XX)           += jornada680_kbd.o
 obj-$(CONFIG_KEYBOARD_HP7XX)           += jornada720_kbd.o
 obj-$(CONFIG_KEYBOARD_LKKBD)           += lkkbd.o
index 1edb596d927bd885dea073593a3183fc63b45a54..b5142d2d5112a0470cf34e924e9c0063124d56f3 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * File: drivers/input/keyboard/adp5588_keys.c
- * Description:  keypad driver for ADP5588 I2C QWERTY Keypad and IO Expander
+ * Description:  keypad driver for ADP5588 and ADP5587
+ *              I2C QWERTY Keypad and IO Expander
  * Bugs: Enter bugs at http://blackfin.uclinux.org/
  *
  * Copyright (C) 2008-2009 Analog Devices Inc.
@@ -327,6 +328,7 @@ static const struct dev_pm_ops adp5588_dev_pm_ops = {
 
 static const struct i2c_device_id adp5588_id[] = {
        { KBUILD_MODNAME, 0 },
+       { "adp5587-keys", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, adp5588_id);
@@ -357,5 +359,5 @@ module_exit(adp5588_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
-MODULE_DESCRIPTION("ADP5588 Keypad driver");
+MODULE_DESCRIPTION("ADP5588/87 Keypad driver");
 MODULE_ALIAS("platform:adp5588-keys");
index 7b4056292eaf9387b95fe80c147ad6c9a65920e5..d358ef8623f490709875b901d82580b1afc7a7fc 100644 (file)
@@ -40,26 +40,26 @@ module_param_named(set, atkbd_set, int, 0);
 MODULE_PARM_DESC(set, "Select keyboard code set (2 = default, 3 = PS/2 native)");
 
 #if defined(__i386__) || defined(__x86_64__) || defined(__hppa__)
-static int atkbd_reset;
+static bool atkbd_reset;
 #else
-static int atkbd_reset = 1;
+static bool atkbd_reset = true;
 #endif
 module_param_named(reset, atkbd_reset, bool, 0);
 MODULE_PARM_DESC(reset, "Reset keyboard during initialization");
 
-static int atkbd_softrepeat;
+static bool atkbd_softrepeat;
 module_param_named(softrepeat, atkbd_softrepeat, bool, 0);
 MODULE_PARM_DESC(softrepeat, "Use software keyboard repeat");
 
-static int atkbd_softraw = 1;
+static bool atkbd_softraw = true;
 module_param_named(softraw, atkbd_softraw, bool, 0);
 MODULE_PARM_DESC(softraw, "Use software generated rawmode");
 
-static int atkbd_scroll;
+static bool atkbd_scroll;
 module_param_named(scroll, atkbd_scroll, bool, 0);
 MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards");
 
-static int atkbd_extra;
+static bool atkbd_extra;
 module_param_named(extra, atkbd_extra, bool, 0);
 MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and similar keyboards");
 
@@ -153,16 +153,16 @@ static const unsigned short atkbd_unxlate_table[128] = {
 #define ATKBD_RET_HANGEUL      0xf2
 #define ATKBD_RET_ERR          0xff
 
-#define ATKBD_KEY_UNKNOWN        0
+#define ATKBD_KEY_UNKNOWN      0
 #define ATKBD_KEY_NULL         255
 
-#define ATKBD_SCR_1            254
-#define ATKBD_SCR_2            253
-#define ATKBD_SCR_4            252
-#define ATKBD_SCR_8            251
-#define ATKBD_SCR_CLICK                250
-#define ATKBD_SCR_LEFT         249
-#define ATKBD_SCR_RIGHT                248
+#define ATKBD_SCR_1            0xfffe
+#define ATKBD_SCR_2            0xfffd
+#define ATKBD_SCR_4            0xfffc
+#define ATKBD_SCR_8            0xfffb
+#define ATKBD_SCR_CLICK                0xfffa
+#define ATKBD_SCR_LEFT         0xfff9
+#define ATKBD_SCR_RIGHT                0xfff8
 
 #define ATKBD_SPECIAL          ATKBD_SCR_RIGHT
 
@@ -177,7 +177,7 @@ static const unsigned short atkbd_unxlate_table[128] = {
 #define ATKBD_XL_HANJA         0x20
 
 static const struct {
-       unsigned char keycode;
+       unsigned short keycode;
        unsigned char set2;
 } atkbd_scroll_keys[] = {
        { ATKBD_SCR_1,     0xc5 },
@@ -206,18 +206,18 @@ struct atkbd {
        unsigned short keycode[ATKBD_KEYMAP_SIZE];
        DECLARE_BITMAP(force_release_mask, ATKBD_KEYMAP_SIZE);
        unsigned char set;
-       unsigned char translated;
-       unsigned char extra;
-       unsigned char write;
-       unsigned char softrepeat;
-       unsigned char softraw;
-       unsigned char scroll;
-       unsigned char enabled;
+       bool translated;
+       bool extra;
+       bool write;
+       bool softrepeat;
+       bool softraw;
+       bool scroll;
+       bool enabled;
 
        /* Accessed only from interrupt */
        unsigned char emul;
-       unsigned char resend;
-       unsigned char release;
+       bool resend;
+       bool release;
        unsigned long xl_bit;
        unsigned int last;
        unsigned long time;
@@ -301,18 +301,18 @@ static const unsigned int xl_table[] = {
  * Checks if we should mangle the scancode to extract 'release' bit
  * in translated mode.
  */
-static int atkbd_need_xlate(unsigned long xl_bit, unsigned char code)
+static bool atkbd_need_xlate(unsigned long xl_bit, unsigned char code)
 {
        int i;
 
        if (code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1)
-               return 0;
+               return false;
 
        for (i = 0; i < ARRAY_SIZE(xl_table); i++)
                if (code == xl_table[i])
                        return test_bit(i, &xl_bit);
 
-       return 1;
+       return true;
 }
 
 /*
@@ -359,7 +359,7 @@ static unsigned int atkbd_compat_scancode(struct atkbd *atkbd, unsigned int code
  */
 
 static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
-                       unsigned int flags)
+                                  unsigned int flags)
 {
        struct atkbd *atkbd = serio_get_drvdata(serio);
        struct input_dev *dev = atkbd->dev;
@@ -368,20 +368,18 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
        int value;
        unsigned short keycode;
 
-#ifdef ATKBD_DEBUG
-       printk(KERN_DEBUG "atkbd.c: Received %02x flags %02x\n", data, flags);
-#endif
+       dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, flags);
 
 #if !defined(__i386__) && !defined (__x86_64__)
        if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && !atkbd->resend && atkbd->write) {
-               printk(KERN_WARNING "atkbd.c: frame/parity error: %02x\n", flags);
+               dev_warn(&serio->dev, "Frame/parity error: %02x\n", flags);
                serio_write(serio, ATKBD_CMD_RESEND);
-               atkbd->resend = 1;
+               atkbd->resend = true;
                goto out;
        }
 
        if (!flags && data == ATKBD_RET_ACK)
-               atkbd->resend = 0;
+               atkbd->resend = false;
 #endif
 
        if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_ACK))
@@ -412,32 +410,32 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
        }
 
        switch (code) {
-               case ATKBD_RET_BAT:
-                       atkbd->enabled = 0;
-                       serio_reconnect(atkbd->ps2dev.serio);
-                       goto out;
-               case ATKBD_RET_EMUL0:
-                       atkbd->emul = 1;
-                       goto out;
-               case ATKBD_RET_EMUL1:
-                       atkbd->emul = 2;
-                       goto out;
-               case ATKBD_RET_RELEASE:
-                       atkbd->release = 1;
-                       goto out;
-               case ATKBD_RET_ACK:
-               case ATKBD_RET_NAK:
-                       if (printk_ratelimit())
-                               printk(KERN_WARNING "atkbd.c: Spurious %s on %s. "
-                                      "Some program might be trying access hardware directly.\n",
-                                      data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
-                       goto out;
-               case ATKBD_RET_ERR:
-                       atkbd->err_count++;
-#ifdef ATKBD_DEBUG
-                       printk(KERN_DEBUG "atkbd.c: Keyboard on %s reports too many keys pressed.\n", serio->phys);
-#endif
-                       goto out;
+       case ATKBD_RET_BAT:
+               atkbd->enabled = false;
+               serio_reconnect(atkbd->ps2dev.serio);
+               goto out;
+       case ATKBD_RET_EMUL0:
+               atkbd->emul = 1;
+               goto out;
+       case ATKBD_RET_EMUL1:
+               atkbd->emul = 2;
+               goto out;
+       case ATKBD_RET_RELEASE:
+               atkbd->release = true;
+               goto out;
+       case ATKBD_RET_ACK:
+       case ATKBD_RET_NAK:
+               if (printk_ratelimit())
+                       dev_warn(&serio->dev,
+                                "Spurious %s on %s. "
+                                "Some program might be trying access hardware directly.\n",
+                                data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
+               goto out;
+       case ATKBD_RET_ERR:
+               atkbd->err_count++;
+               dev_dbg(&serio->dev, "Keyboard on %s reports too many keys pressed.\n",
+                       serio->phys);
+               goto out;
        }
 
        code = atkbd_compat_scancode(atkbd, code);
@@ -451,71 +449,72 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
                input_event(dev, EV_MSC, MSC_SCAN, code);
 
        switch (keycode) {
-               case ATKBD_KEY_NULL:
-                       break;
-               case ATKBD_KEY_UNKNOWN:
-                       printk(KERN_WARNING
-                              "atkbd.c: Unknown key %s (%s set %d, code %#x on %s).\n",
-                              atkbd->release ? "released" : "pressed",
-                              atkbd->translated ? "translated" : "raw",
-                              atkbd->set, code, serio->phys);
-                       printk(KERN_WARNING
-                              "atkbd.c: Use 'setkeycodes %s%02x <keycode>' to make it known.\n",
-                              code & 0x80 ? "e0" : "", code & 0x7f);
-                       input_sync(dev);
-                       break;
-               case ATKBD_SCR_1:
-                       scroll = 1 - atkbd->release * 2;
-                       break;
-               case ATKBD_SCR_2:
-                       scroll = 2 - atkbd->release * 4;
-                       break;
-               case ATKBD_SCR_4:
-                       scroll = 4 - atkbd->release * 8;
-                       break;
-               case ATKBD_SCR_8:
-                       scroll = 8 - atkbd->release * 16;
-                       break;
-               case ATKBD_SCR_CLICK:
-                       click = !atkbd->release;
-                       break;
-               case ATKBD_SCR_LEFT:
-                       hscroll = -1;
-                       break;
-               case ATKBD_SCR_RIGHT:
-                       hscroll = 1;
-                       break;
-               default:
-                       if (atkbd->release) {
-                               value = 0;
-                               atkbd->last = 0;
-                       } else if (!atkbd->softrepeat && test_bit(keycode, dev->key)) {
-                               /* Workaround Toshiba laptop multiple keypress */
-                               value = time_before(jiffies, atkbd->time) && atkbd->last == code ? 1 : 2;
-                       } else {
-                               value = 1;
-                               atkbd->last = code;
-                               atkbd->time = jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]) / 2;
-                       }
-
-                       input_event(dev, EV_KEY, keycode, value);
-                       input_sync(dev);
+       case ATKBD_KEY_NULL:
+               break;
+       case ATKBD_KEY_UNKNOWN:
+               dev_warn(&serio->dev,
+                        "Unknown key %s (%s set %d, code %#x on %s).\n",
+                        atkbd->release ? "released" : "pressed",
+                        atkbd->translated ? "translated" : "raw",
+                        atkbd->set, code, serio->phys);
+               dev_warn(&serio->dev,
+                        "Use 'setkeycodes %s%02x <keycode>' to make it known.\n",
+                        code & 0x80 ? "e0" : "", code & 0x7f);
+               input_sync(dev);
+               break;
+       case ATKBD_SCR_1:
+               scroll = 1;
+               break;
+       case ATKBD_SCR_2:
+               scroll = 2;
+               break;
+       case ATKBD_SCR_4:
+               scroll = 4;
+               break;
+       case ATKBD_SCR_8:
+               scroll = 8;
+               break;
+       case ATKBD_SCR_CLICK:
+               click = !atkbd->release;
+               break;
+       case ATKBD_SCR_LEFT:
+               hscroll = -1;
+               break;
+       case ATKBD_SCR_RIGHT:
+               hscroll = 1;
+               break;
+       default:
+               if (atkbd->release) {
+                       value = 0;
+                       atkbd->last = 0;
+               } else if (!atkbd->softrepeat && test_bit(keycode, dev->key)) {
+                       /* Workaround Toshiba laptop multiple keypress */
+                       value = time_before(jiffies, atkbd->time) && atkbd->last == code ? 1 : 2;
+               } else {
+                       value = 1;
+                       atkbd->last = code;
+                       atkbd->time = jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]) / 2;
+               }
+
+               input_event(dev, EV_KEY, keycode, value);
+               input_sync(dev);
 
-                       if (value && test_bit(code, atkbd->force_release_mask)) {
-                               input_report_key(dev, keycode, 0);
-                               input_sync(dev);
-                       }
+               if (value && test_bit(code, atkbd->force_release_mask)) {
+                       input_report_key(dev, keycode, 0);
+                       input_sync(dev);
+               }
        }
 
        if (atkbd->scroll) {
                if (click != -1)
                        input_report_key(dev, BTN_MIDDLE, click);
-               input_report_rel(dev, REL_WHEEL, scroll);
+               input_report_rel(dev, REL_WHEEL,
+                                atkbd->release ? -scroll : scroll);
                input_report_rel(dev, REL_HWHEEL, hscroll);
                input_sync(dev);
        }
 
-       atkbd->release = 0;
+       atkbd->release = false;
 out:
        return IRQ_HANDLED;
 }
@@ -634,17 +633,18 @@ static int atkbd_event(struct input_dev *dev,
 
        switch (type) {
 
-               case EV_LED:
-                       atkbd_schedule_event_work(atkbd, ATKBD_LED_EVENT_BIT);
-                       return 0;
+       case EV_LED:
+               atkbd_schedule_event_work(atkbd, ATKBD_LED_EVENT_BIT);
+               return 0;
 
-               case EV_REP:
-                       if (!atkbd->softrepeat)
-                               atkbd_schedule_event_work(atkbd, ATKBD_REP_EVENT_BIT);
-                       return 0;
-       }
+       case EV_REP:
+               if (!atkbd->softrepeat)
+                       atkbd_schedule_event_work(atkbd, ATKBD_REP_EVENT_BIT);
+               return 0;
 
-       return -1;
+       default:
+               return -1;
+       }
 }
 
 /*
@@ -655,7 +655,7 @@ static int atkbd_event(struct input_dev *dev,
 static inline void atkbd_enable(struct atkbd *atkbd)
 {
        serio_pause_rx(atkbd->ps2dev.serio);
-       atkbd->enabled = 1;
+       atkbd->enabled = true;
        serio_continue_rx(atkbd->ps2dev.serio);
 }
 
@@ -667,7 +667,7 @@ static inline void atkbd_enable(struct atkbd *atkbd)
 static inline void atkbd_disable(struct atkbd *atkbd)
 {
        serio_pause_rx(atkbd->ps2dev.serio);
-       atkbd->enabled = 0;
+       atkbd->enabled = false;
        serio_continue_rx(atkbd->ps2dev.serio);
 }
 
@@ -688,7 +688,9 @@ static int atkbd_probe(struct atkbd *atkbd)
 
        if (atkbd_reset)
                if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_BAT))
-                       printk(KERN_WARNING "atkbd.c: keyboard reset failed on %s\n", ps2dev->serio->phys);
+                       dev_warn(&ps2dev->serio->dev,
+                                "keyboard reset failed on %s\n",
+                                ps2dev->serio->phys);
 
 /*
  * Then we check the keyboard ID. We should get 0xab83 under normal conditions.
@@ -718,8 +720,9 @@ static int atkbd_probe(struct atkbd *atkbd)
        atkbd->id = (param[0] << 8) | param[1];
 
        if (atkbd->id == 0xaca1 && atkbd->translated) {
-               printk(KERN_ERR "atkbd.c: NCD terminal keyboards are only supported on non-translating\n");
-               printk(KERN_ERR "atkbd.c: controllers. Use i8042.direct=1 to disable translation.\n");
+               dev_err(&ps2dev->serio->dev,
+                       "NCD terminal keyboards are only supported on non-translating controlelrs. "
+                       "Use i8042.direct=1 to disable translation.\n");
                return -1;
        }
 
@@ -737,7 +740,7 @@ static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra
        struct ps2dev *ps2dev = &atkbd->ps2dev;
        unsigned char param[2];
 
-       atkbd->extra = 0;
+       atkbd->extra = false;
 /*
  * For known special keyboards we can go ahead and set the correct set.
  * We check for NCD PS/2 Sun, NorthGate OmniKey 101 and
@@ -756,7 +759,7 @@ static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra
        if (allow_extra) {
                param[0] = 0x71;
                if (!ps2_command(ps2dev, param, ATKBD_CMD_EX_ENABLE)) {
-                       atkbd->extra = 1;
+                       atkbd->extra = true;
                        return 2;
                }
        }
@@ -821,7 +824,8 @@ static int atkbd_activate(struct atkbd *atkbd)
  */
 
        if (ps2_command(ps2dev, NULL, ATKBD_CMD_ENABLE)) {
-               printk(KERN_ERR "atkbd.c: Failed to enable keyboard on %s\n",
+               dev_err(&ps2dev->serio->dev,
+                       "Failed to enable keyboard on %s\n",
                        ps2dev->serio->phys);
                return -1;
        }
@@ -1070,9 +1074,13 @@ static void atkbd_set_device_attrs(struct atkbd *atkbd)
        input_dev->keycodesize = sizeof(unsigned short);
        input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode);
 
-       for (i = 0; i < ATKBD_KEYMAP_SIZE; i++)
-               if (atkbd->keycode[i] && atkbd->keycode[i] < ATKBD_SPECIAL)
+       for (i = 0; i < ATKBD_KEYMAP_SIZE; i++) {
+               if (atkbd->keycode[i] != KEY_RESERVED &&
+                   atkbd->keycode[i] != ATKBD_KEY_NULL &&
+                   atkbd->keycode[i] < ATKBD_SPECIAL) {
                        __set_bit(atkbd->keycode[i], input_dev->keybit);
+               }
+       }
 }
 
 /*
@@ -1100,12 +1108,14 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
 
        switch (serio->id.type) {
 
-               case SERIO_8042_XL:
-                       atkbd->translated = 1;
-               case SERIO_8042:
-                       if (serio->write)
-                               atkbd->write = 1;
-                       break;
+       case SERIO_8042_XL:
+               atkbd->translated = true;
+               /* Fall through */
+
+       case SERIO_8042:
+               if (serio->write)
+                       atkbd->write = true;
+               break;
        }
 
        atkbd->softraw = atkbd_softraw;
@@ -1113,7 +1123,7 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
        atkbd->scroll = atkbd_scroll;
 
        if (atkbd->softrepeat)
-               atkbd->softraw = 1;
+               atkbd->softraw = true;
 
        serio_set_drvdata(serio, atkbd);
 
@@ -1172,7 +1182,8 @@ static int atkbd_reconnect(struct serio *serio)
        int retval = -1;
 
        if (!atkbd || !drv) {
-               printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n");
+               dev_dbg(&serio->dev,
+                       "reconnect request, but serio is disconnected, ignoring...\n");
                return -1;
        }
 
@@ -1286,7 +1297,8 @@ static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t coun
        struct input_dev *old_dev, *new_dev;
        unsigned long value;
        int err;
-       unsigned char old_extra, old_set;
+       bool old_extra;
+       unsigned char old_set;
 
        if (!atkbd->write)
                return -EIO;
@@ -1369,7 +1381,7 @@ static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t cou
        struct input_dev *old_dev, *new_dev;
        unsigned long value;
        int err;
-       unsigned char old_scroll;
+       bool old_scroll;
 
        if (strict_strtoul(buf, 10, &value) || value > 1)
                return -EINVAL;
@@ -1413,7 +1425,8 @@ static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count)
        struct input_dev *old_dev, *new_dev;
        unsigned long value;
        int err;
-       unsigned char old_set, old_extra;
+       unsigned char old_set;
+       bool old_extra;
 
        if (!atkbd->write)
                return -EIO;
@@ -1463,7 +1476,7 @@ static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t
        struct input_dev *old_dev, *new_dev;
        unsigned long value;
        int err;
-       unsigned char old_softrepeat, old_softraw;
+       bool old_softrepeat, old_softraw;
 
        if (!atkbd->write)
                return -EIO;
@@ -1483,7 +1496,7 @@ static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t
                atkbd->dev = new_dev;
                atkbd->softrepeat = value;
                if (atkbd->softrepeat)
-                       atkbd->softraw = 1;
+                       atkbd->softraw = true;
                atkbd_set_device_attrs(atkbd);
 
                err = input_register_device(atkbd->dev);
@@ -1513,7 +1526,7 @@ static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t co
        struct input_dev *old_dev, *new_dev;
        unsigned long value;
        int err;
-       unsigned char old_softraw;
+       bool old_softraw;
 
        if (strict_strtoul(buf, 10, &value) || value > 1)
                return -EINVAL;
index e45740429f7e4e34db3e08e6c9698df2632fb640..bd25a3af16644a63885e7be741bb6a97728a7329 100644 (file)
@@ -69,7 +69,7 @@ struct ep93xx_keypad {
 
        void __iomem *mmio_base;
 
-       unsigned int matrix_keycodes[EP93XX_MATRIX_SIZE];
+       unsigned short keycodes[EP93XX_MATRIX_SIZE];
 
        int key1;
        int key2;
@@ -79,24 +79,6 @@ struct ep93xx_keypad {
        bool enabled;
 };
 
-static void ep93xx_keypad_build_keycode(struct ep93xx_keypad *keypad)
-{
-       struct ep93xx_keypad_platform_data *pdata = keypad->pdata;
-       struct input_dev *input_dev = keypad->input_dev;
-       unsigned int *key;
-       int i;
-
-       key = &pdata->matrix_key_map[0];
-       for (i = 0; i < pdata->matrix_key_map_size; i++, key++) {
-               int row = KEY_ROW(*key);
-               int col = KEY_COL(*key);
-               int code = KEY_VAL(*key);
-
-               keypad->matrix_keycodes[(row << 3) + col] = code;
-               __set_bit(code, input_dev->keybit);
-       }
-}
-
 static irqreturn_t ep93xx_keypad_irq_handler(int irq, void *dev_id)
 {
        struct ep93xx_keypad *keypad = dev_id;
@@ -107,10 +89,10 @@ static irqreturn_t ep93xx_keypad_irq_handler(int irq, void *dev_id)
        status = __raw_readl(keypad->mmio_base + KEY_REG);
 
        keycode = (status & KEY_REG_KEY1_MASK) >> KEY_REG_KEY1_SHIFT;
-       key1 = keypad->matrix_keycodes[keycode];
+       key1 = keypad->keycodes[keycode];
 
        keycode = (status & KEY_REG_KEY2_MASK) >> KEY_REG_KEY2_SHIFT;
-       key2 = keypad->matrix_keycodes[keycode];
+       key2 = keypad->keycodes[keycode];
 
        if (status & KEY_REG_2KEYS) {
                if (keypad->key1 && key1 != keypad->key1 && key2 != keypad->key1)
@@ -256,6 +238,7 @@ static int ep93xx_keypad_resume(struct platform_device *pdev)
 static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
 {
        struct ep93xx_keypad *keypad;
+       const struct matrix_keymap_data *keymap_data;
        struct input_dev *input_dev;
        struct resource *res;
        int err;
@@ -270,6 +253,12 @@ static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
                goto failed_free;
        }
 
+       keymap_data = keypad->pdata->keymap_data;
+       if (!keymap_data) {
+               err = -EINVAL;
+               goto failed_free;
+       }
+
        keypad->irq = platform_get_irq(pdev, 0);
        if (!keypad->irq) {
                err = -ENXIO;
@@ -317,9 +306,9 @@ static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
        input_dev->open = ep93xx_keypad_open;
        input_dev->close = ep93xx_keypad_close;
        input_dev->dev.parent = &pdev->dev;
-       input_dev->keycode = keypad->matrix_keycodes;
-       input_dev->keycodesize = sizeof(keypad->matrix_keycodes[0]);
-       input_dev->keycodemax = ARRAY_SIZE(keypad->matrix_keycodes);
+       input_dev->keycode = keypad->keycodes;
+       input_dev->keycodesize = sizeof(keypad->keycodes[0]);
+       input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
 
        input_set_drvdata(input_dev, keypad);
 
@@ -327,7 +316,8 @@ static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
        if (keypad->pdata->flags & EP93XX_KEYPAD_AUTOREPEAT)
                input_dev->evbit[0] |= BIT_MASK(EV_REP);
 
-       ep93xx_keypad_build_keycode(keypad);
+       matrix_keypad_build_keymap(keymap_data, 3,
+                                  input_dev->keycode, input_dev->keybit);
        platform_set_drvdata(pdev, keypad);
 
        err = request_irq(keypad->irq, ep93xx_keypad_irq_handler,
index 1aff3b76effdb0b05ee4201cba2525cce5b44769..2b708aa85553358a2b375cbb602fb07d1ea36c02 100644 (file)
@@ -30,13 +30,289 @@ struct gpio_button_data {
        struct input_dev *input;
        struct timer_list timer;
        struct work_struct work;
+       bool disabled;
 };
 
 struct gpio_keys_drvdata {
        struct input_dev *input;
+       struct mutex disable_lock;
+       unsigned int n_buttons;
        struct gpio_button_data data[0];
 };
 
+/*
+ * SYSFS interface for enabling/disabling keys and switches:
+ *
+ * There are 4 attributes under /sys/devices/platform/gpio-keys/
+ *     keys [ro]              - bitmap of keys (EV_KEY) which can be
+ *                              disabled
+ *     switches [ro]          - bitmap of switches (EV_SW) which can be
+ *                              disabled
+ *     disabled_keys [rw]     - bitmap of keys currently disabled
+ *     disabled_switches [rw] - bitmap of switches currently disabled
+ *
+ * Userland can change these values and hence disable event generation
+ * for each key (or switch). Disabling a key means its interrupt line
+ * is disabled.
+ *
+ * For example, if we have following switches set up as gpio-keys:
+ *     SW_DOCK = 5
+ *     SW_CAMERA_LENS_COVER = 9
+ *     SW_KEYPAD_SLIDE = 10
+ *     SW_FRONT_PROXIMITY = 11
+ * This is read from switches:
+ *     11-9,5
+ * Next we want to disable proximity (11) and dock (5), we write:
+ *     11,5
+ * to file disabled_switches. Now proximity and dock IRQs are disabled.
+ * This can be verified by reading the file disabled_switches:
+ *     11,5
+ * If we now want to enable proximity (11) switch we write:
+ *     5
+ * to disabled_switches.
+ *
+ * We can disable only those keys which don't allow sharing the irq.
+ */
+
+/**
+ * get_n_events_by_type() - returns maximum number of events per @type
+ * @type: type of button (%EV_KEY, %EV_SW)
+ *
+ * Return value of this function can be used to allocate bitmap
+ * large enough to hold all bits for given type.
+ */
+static inline int get_n_events_by_type(int type)
+{
+       BUG_ON(type != EV_SW && type != EV_KEY);
+
+       return (type == EV_KEY) ? KEY_CNT : SW_CNT;
+}
+
+/**
+ * gpio_keys_disable_button() - disables given GPIO button
+ * @bdata: button data for button to be disabled
+ *
+ * Disables button pointed by @bdata. This is done by masking
+ * IRQ line. After this function is called, button won't generate
+ * input events anymore. Note that one can only disable buttons
+ * that don't share IRQs.
+ *
+ * Make sure that @bdata->disable_lock is locked when entering
+ * this function to avoid races when concurrent threads are
+ * disabling buttons at the same time.
+ */
+static void gpio_keys_disable_button(struct gpio_button_data *bdata)
+{
+       if (!bdata->disabled) {
+               /*
+                * Disable IRQ and possible debouncing timer.
+                */
+               disable_irq(gpio_to_irq(bdata->button->gpio));
+               if (bdata->button->debounce_interval)
+                       del_timer_sync(&bdata->timer);
+
+               bdata->disabled = true;
+       }
+}
+
+/**
+ * gpio_keys_enable_button() - enables given GPIO button
+ * @bdata: button data for button to be disabled
+ *
+ * Enables given button pointed by @bdata.
+ *
+ * Make sure that @bdata->disable_lock is locked when entering
+ * this function to avoid races with concurrent threads trying
+ * to enable the same button at the same time.
+ */
+static void gpio_keys_enable_button(struct gpio_button_data *bdata)
+{
+       if (bdata->disabled) {
+               enable_irq(gpio_to_irq(bdata->button->gpio));
+               bdata->disabled = false;
+       }
+}
+
+/**
+ * gpio_keys_attr_show_helper() - fill in stringified bitmap of buttons
+ * @ddata: pointer to drvdata
+ * @buf: buffer where stringified bitmap is written
+ * @type: button type (%EV_KEY, %EV_SW)
+ * @only_disabled: does caller want only those buttons that are
+ *                 currently disabled or all buttons that can be
+ *                 disabled
+ *
+ * This function writes buttons that can be disabled to @buf. If
+ * @only_disabled is true, then @buf contains only those buttons
+ * that are currently disabled. Returns 0 on success or negative
+ * errno on failure.
+ */
+static ssize_t gpio_keys_attr_show_helper(struct gpio_keys_drvdata *ddata,
+                                         char *buf, unsigned int type,
+                                         bool only_disabled)
+{
+       int n_events = get_n_events_by_type(type);
+       unsigned long *bits;
+       ssize_t ret;
+       int i;
+
+       bits = kcalloc(BITS_TO_LONGS(n_events), sizeof(*bits), GFP_KERNEL);
+       if (!bits)
+               return -ENOMEM;
+
+       for (i = 0; i < ddata->n_buttons; i++) {
+               struct gpio_button_data *bdata = &ddata->data[i];
+
+               if (bdata->button->type != type)
+                       continue;
+
+               if (only_disabled && !bdata->disabled)
+                       continue;
+
+               __set_bit(bdata->button->code, bits);
+       }
+
+       ret = bitmap_scnlistprintf(buf, PAGE_SIZE - 2, bits, n_events);
+       buf[ret++] = '\n';
+       buf[ret] = '\0';
+
+       kfree(bits);
+
+       return ret;
+}
+
+/**
+ * gpio_keys_attr_store_helper() - enable/disable buttons based on given bitmap
+ * @ddata: pointer to drvdata
+ * @buf: buffer from userspace that contains stringified bitmap
+ * @type: button type (%EV_KEY, %EV_SW)
+ *
+ * This function parses stringified bitmap from @buf and disables/enables
+ * GPIO buttons accordinly. Returns 0 on success and negative error
+ * on failure.
+ */
+static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
+                                          const char *buf, unsigned int type)
+{
+       int n_events = get_n_events_by_type(type);
+       unsigned long *bits;
+       ssize_t error;
+       int i;
+
+       bits = kcalloc(BITS_TO_LONGS(n_events), sizeof(*bits), GFP_KERNEL);
+       if (!bits)
+               return -ENOMEM;
+
+       error = bitmap_parselist(buf, bits, n_events);
+       if (error)
+               goto out;
+
+       /* First validate */
+       for (i = 0; i < ddata->n_buttons; i++) {
+               struct gpio_button_data *bdata = &ddata->data[i];
+
+               if (bdata->button->type != type)
+                       continue;
+
+               if (test_bit(bdata->button->code, bits) &&
+                   !bdata->button->can_disable) {
+                       error = -EINVAL;
+                       goto out;
+               }
+       }
+
+       mutex_lock(&ddata->disable_lock);
+
+       for (i = 0; i < ddata->n_buttons; i++) {
+               struct gpio_button_data *bdata = &ddata->data[i];
+
+               if (bdata->button->type != type)
+                       continue;
+
+               if (test_bit(bdata->button->code, bits))
+                       gpio_keys_disable_button(bdata);
+               else
+                       gpio_keys_enable_button(bdata);
+       }
+
+       mutex_unlock(&ddata->disable_lock);
+
+out:
+       kfree(bits);
+       return error;
+}
+
+#define ATTR_SHOW_FN(name, type, only_disabled)                                \
+static ssize_t gpio_keys_show_##name(struct device *dev,               \
+                                    struct device_attribute *attr,     \
+                                    char *buf)                         \
+{                                                                      \
+       struct platform_device *pdev = to_platform_device(dev);         \
+       struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);   \
+                                                                       \
+       return gpio_keys_attr_show_helper(ddata, buf,                   \
+                                         type, only_disabled);         \
+}
+
+ATTR_SHOW_FN(keys, EV_KEY, false);
+ATTR_SHOW_FN(switches, EV_SW, false);
+ATTR_SHOW_FN(disabled_keys, EV_KEY, true);
+ATTR_SHOW_FN(disabled_switches, EV_SW, true);
+
+/*
+ * ATTRIBUTES:
+ *
+ * /sys/devices/platform/gpio-keys/keys [ro]
+ * /sys/devices/platform/gpio-keys/switches [ro]
+ */
+static DEVICE_ATTR(keys, S_IRUGO, gpio_keys_show_keys, NULL);
+static DEVICE_ATTR(switches, S_IRUGO, gpio_keys_show_switches, NULL);
+
+#define ATTR_STORE_FN(name, type)                                      \
+static ssize_t gpio_keys_store_##name(struct device *dev,              \
+                                     struct device_attribute *attr,    \
+                                     const char *buf,                  \
+                                     size_t count)                     \
+{                                                                      \
+       struct platform_device *pdev = to_platform_device(dev);         \
+       struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);   \
+       ssize_t error;                                                  \
+                                                                       \
+       error = gpio_keys_attr_store_helper(ddata, buf, type);          \
+       if (error)                                                      \
+               return error;                                           \
+                                                                       \
+       return count;                                                   \
+}
+
+ATTR_STORE_FN(disabled_keys, EV_KEY);
+ATTR_STORE_FN(disabled_switches, EV_SW);
+
+/*
+ * ATTRIBUTES:
+ *
+ * /sys/devices/platform/gpio-keys/disabled_keys [rw]
+ * /sys/devices/platform/gpio-keys/disables_switches [rw]
+ */
+static DEVICE_ATTR(disabled_keys, S_IWUSR | S_IRUGO,
+                  gpio_keys_show_disabled_keys,
+                  gpio_keys_store_disabled_keys);
+static DEVICE_ATTR(disabled_switches, S_IWUSR | S_IRUGO,
+                  gpio_keys_show_disabled_switches,
+                  gpio_keys_store_disabled_switches);
+
+static struct attribute *gpio_keys_attrs[] = {
+       &dev_attr_keys.attr,
+       &dev_attr_switches.attr,
+       &dev_attr_disabled_keys.attr,
+       &dev_attr_disabled_switches.attr,
+       NULL,
+};
+
+static struct attribute_group gpio_keys_attr_group = {
+       .attrs = gpio_keys_attrs,
+};
+
 static void gpio_keys_report_event(struct gpio_button_data *bdata)
 {
        struct gpio_keys_button *button = bdata->button;
@@ -79,11 +355,13 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit gpio_keys_setup_key(struct device *dev,
+static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
                                         struct gpio_button_data *bdata,
                                         struct gpio_keys_button *button)
 {
        char *desc = button->desc ? button->desc : "gpio_keys";
+       struct device *dev = &pdev->dev;
+       unsigned long irqflags;
        int irq, error;
 
        setup_timer(&bdata->timer, gpio_keys_timer, (unsigned long)bdata);
@@ -112,10 +390,15 @@ static int __devinit gpio_keys_setup_key(struct device *dev,
                goto fail3;
        }
 
-       error = request_irq(irq, gpio_keys_isr,
-                           IRQF_SHARED |
-                           IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-                           desc, bdata);
+       irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
+       /*
+        * If platform has specified that the button can be disabled,
+        * we don't want it to share the interrupt line.
+        */
+       if (!button->can_disable)
+               irqflags |= IRQF_SHARED;
+
+       error = request_irq(irq, gpio_keys_isr, irqflags, desc, bdata);
        if (error) {
                dev_err(dev, "Unable to claim irq %d; error %d\n",
                        irq, error);
@@ -149,6 +432,10 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
                goto fail1;
        }
 
+       ddata->input = input;
+       ddata->n_buttons = pdata->nbuttons;
+       mutex_init(&ddata->disable_lock);
+
        platform_set_drvdata(pdev, ddata);
 
        input->name = pdev->name;
@@ -164,8 +451,6 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
        if (pdata->rep)
                __set_bit(EV_REP, input->evbit);
 
-       ddata->input = input;
-
        for (i = 0; i < pdata->nbuttons; i++) {
                struct gpio_keys_button *button = &pdata->buttons[i];
                struct gpio_button_data *bdata = &ddata->data[i];
@@ -174,7 +459,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
                bdata->input = input;
                bdata->button = button;
 
-               error = gpio_keys_setup_key(dev, bdata, button);
+               error = gpio_keys_setup_key(pdev, bdata, button);
                if (error)
                        goto fail2;
 
@@ -184,13 +469,20 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
                input_set_capability(input, type, button->code);
        }
 
-       error = input_register_device(input);
+       error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group);
        if (error) {
-               dev_err(dev, "Unable to register input device, "
-                       "error: %d\n", error);
+               dev_err(dev, "Unable to export keys/switches, error: %d\n",
+                       error);
                goto fail2;
        }
 
+       error = input_register_device(input);
+       if (error) {
+               dev_err(dev, "Unable to register input device, error: %d\n",
+                       error);
+               goto fail3;
+       }
+
        /* get current state of buttons */
        for (i = 0; i < pdata->nbuttons; i++)
                gpio_keys_report_event(&ddata->data[i]);
@@ -200,6 +492,8 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
 
        return 0;
 
+ fail3:
+       sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
  fail2:
        while (--i >= 0) {
                free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]);
@@ -224,6 +518,8 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
        struct input_dev *input = ddata->input;
        int i;
 
+       sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
+
        device_init_wakeup(&pdev->dev, 0);
 
        for (i = 0; i < pdata->nbuttons; i++) {
diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c
new file mode 100644 (file)
index 0000000..2ee5b79
--- /dev/null
@@ -0,0 +1,594 @@
+/*
+ * Driver for the IMX keypad port.
+ * Copyright (C) 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * <<Power management needs to be implemented>>.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/input/matrix_keypad.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/timer.h>
+
+/*
+ * Keypad Controller registers (halfword)
+ */
+#define KPCR           0x00 /* Keypad Control Register */
+
+#define KPSR           0x02 /* Keypad Status Register */
+#define KBD_STAT_KPKD  (0x1 << 0) /* Key Press Interrupt Status bit (w1c) */
+#define KBD_STAT_KPKR  (0x1 << 1) /* Key Release Interrupt Status bit (w1c) */
+#define KBD_STAT_KDSC  (0x1 << 2) /* Key Depress Synch Chain Status bit (w1c)*/
+#define KBD_STAT_KRSS  (0x1 << 3) /* Key Release Synch Status bit (w1c)*/
+#define KBD_STAT_KDIE  (0x1 << 8) /* Key Depress Interrupt Enable Status bit */
+#define KBD_STAT_KRIE  (0x1 << 9) /* Key Release Interrupt Enable */
+#define KBD_STAT_KPPEN (0x1 << 10) /* Keypad Clock Enable */
+
+#define KDDR           0x04 /* Keypad Data Direction Register */
+#define KPDR           0x06 /* Keypad Data Register */
+
+#define MAX_MATRIX_KEY_ROWS    8
+#define MAX_MATRIX_KEY_COLS    8
+#define MATRIX_ROW_SHIFT       3
+
+#define MAX_MATRIX_KEY_NUM     (MAX_MATRIX_KEY_ROWS * MAX_MATRIX_KEY_COLS)
+
+struct imx_keypad {
+
+       struct clk *clk;
+       struct input_dev *input_dev;
+       void __iomem *mmio_base;
+
+       int                     irq;
+       struct timer_list       check_matrix_timer;
+
+       /*
+        * The matrix is stable only if no changes are detected after
+        * IMX_KEYPAD_SCANS_FOR_STABILITY scans
+        */
+#define IMX_KEYPAD_SCANS_FOR_STABILITY 3
+       int                     stable_count;
+
+       bool                    enabled;
+
+       /* Masks for enabled rows/cols */
+       unsigned short          rows_en_mask;
+       unsigned short          cols_en_mask;
+
+       unsigned short          keycodes[MAX_MATRIX_KEY_NUM];
+
+       /*
+        * Matrix states:
+        * -stable: achieved after a complete debounce process.
+        * -unstable: used in the debouncing process.
+        */
+       unsigned short          matrix_stable_state[MAX_MATRIX_KEY_COLS];
+       unsigned short          matrix_unstable_state[MAX_MATRIX_KEY_COLS];
+};
+
+/* Scan the matrix and return the new state in *matrix_volatile_state. */
+static void imx_keypad_scan_matrix(struct imx_keypad *keypad,
+                                 unsigned short *matrix_volatile_state)
+{
+       int col;
+       unsigned short reg_val;
+
+       for (col = 0; col < MAX_MATRIX_KEY_COLS; col++) {
+               if ((keypad->cols_en_mask & (1 << col)) == 0)
+                       continue;
+               /*
+                * Discharge keypad capacitance:
+                * 2. write 1s on column data.
+                * 3. configure columns as totem-pole to discharge capacitance.
+                * 4. configure columns as open-drain.
+                */
+               reg_val = readw(keypad->mmio_base + KPDR);
+               reg_val |= 0xff00;
+               writew(reg_val, keypad->mmio_base + KPDR);
+
+               reg_val = readw(keypad->mmio_base + KPCR);
+               reg_val &= ~((keypad->cols_en_mask & 0xff) << 8);
+               writew(reg_val, keypad->mmio_base + KPCR);
+
+               udelay(2);
+
+               reg_val = readw(keypad->mmio_base + KPCR);
+               reg_val |= (keypad->cols_en_mask & 0xff) << 8;
+               writew(reg_val, keypad->mmio_base + KPCR);
+
+               /*
+                * 5. Write a single column to 0, others to 1.
+                * 6. Sample row inputs and save data.
+                * 7. Repeat steps 2 - 6 for remaining columns.
+                */
+               reg_val = readw(keypad->mmio_base + KPDR);
+               reg_val &= ~(1 << (8 + col));
+               writew(reg_val, keypad->mmio_base + KPDR);
+
+               /*
+                * Delay added to avoid propagating the 0 from column to row
+                * when scanning.
+                */
+               udelay(5);
+
+               /*
+                * 1s in matrix_volatile_state[col] means key pressures
+                * throw data from non enabled rows.
+                */
+               reg_val = readw(keypad->mmio_base + KPDR);
+               matrix_volatile_state[col] = (~reg_val) & keypad->rows_en_mask;
+       }
+
+       /*
+        * Return in standby mode:
+        * 9. write 0s to columns
+        */
+       reg_val = readw(keypad->mmio_base + KPDR);
+       reg_val &= 0x00ff;
+       writew(reg_val, keypad->mmio_base + KPDR);
+}
+
+/*
+ * Compare the new matrix state (volatile) with the stable one stored in
+ * keypad->matrix_stable_state and fire events if changes are detected.
+ */
+static void imx_keypad_fire_events(struct imx_keypad *keypad,
+                                  unsigned short *matrix_volatile_state)
+{
+       struct input_dev *input_dev = keypad->input_dev;
+       int row, col;
+
+       for (col = 0; col < MAX_MATRIX_KEY_COLS; col++) {
+               unsigned short bits_changed;
+               int code;
+
+               if ((keypad->cols_en_mask & (1 << col)) == 0)
+                       continue; /* Column is not enabled */
+
+               bits_changed = keypad->matrix_stable_state[col] ^
+                                               matrix_volatile_state[col];
+
+               if (bits_changed == 0)
+                       continue; /* Column does not contain changes */
+
+               for (row = 0; row < MAX_MATRIX_KEY_ROWS; row++) {
+                       if ((keypad->rows_en_mask & (1 << row)) == 0)
+                               continue; /* Row is not enabled */
+                       if ((bits_changed & (1 << row)) == 0)
+                               continue; /* Row does not contain changes */
+
+                       code = MATRIX_SCAN_CODE(row, col, MATRIX_ROW_SHIFT);
+                       input_event(input_dev, EV_MSC, MSC_SCAN, code);
+                       input_report_key(input_dev, keypad->keycodes[code],
+                               matrix_volatile_state[col] & (1 << row));
+                       dev_dbg(&input_dev->dev, "Event code: %d, val: %d",
+                               keypad->keycodes[code],
+                               matrix_volatile_state[col] & (1 << row));
+               }
+       }
+       input_sync(input_dev);
+}
+
+/*
+ * imx_keypad_check_for_events is the timer handler.
+ */
+static void imx_keypad_check_for_events(unsigned long data)
+{
+       struct imx_keypad *keypad = (struct imx_keypad *) data;
+       unsigned short matrix_volatile_state[MAX_MATRIX_KEY_COLS];
+       unsigned short reg_val;
+       bool state_changed, is_zero_matrix;
+       int i;
+
+       memset(matrix_volatile_state, 0, sizeof(matrix_volatile_state));
+
+       imx_keypad_scan_matrix(keypad, matrix_volatile_state);
+
+       state_changed = false;
+       for (i = 0; i < MAX_MATRIX_KEY_COLS; i++) {
+               if ((keypad->cols_en_mask & (1 << i)) == 0)
+                       continue;
+
+               if (keypad->matrix_unstable_state[i] ^ matrix_volatile_state[i]) {
+                       state_changed = true;
+                       break;
+               }
+       }
+
+       /*
+        * If the matrix state is changed from the previous scan
+        *   (Re)Begin the debouncing process, saving the new state in
+        *    keypad->matrix_unstable_state.
+        * else
+        *   Increase the count of number of scans with a stable state.
+        */
+       if (state_changed) {
+               memcpy(keypad->matrix_unstable_state, matrix_volatile_state,
+                       sizeof(matrix_volatile_state));
+               keypad->stable_count = 0;
+       } else
+               keypad->stable_count++;
+
+       /*
+        * If the matrix is not as stable as we want reschedule scan
+        * in the near future.
+        */
+       if (keypad->stable_count < IMX_KEYPAD_SCANS_FOR_STABILITY) {
+               mod_timer(&keypad->check_matrix_timer,
+                         jiffies + msecs_to_jiffies(10));
+               return;
+       }
+
+       /*
+        * If the matrix state is stable, fire the events and save the new
+        * stable state. Note, if the matrix is kept stable for longer
+        * (keypad->stable_count > IMX_KEYPAD_SCANS_FOR_STABILITY) all
+        * events have already been generated.
+        */
+       if (keypad->stable_count == IMX_KEYPAD_SCANS_FOR_STABILITY) {
+               imx_keypad_fire_events(keypad, matrix_volatile_state);
+
+               memcpy(keypad->matrix_stable_state, matrix_volatile_state,
+                       sizeof(matrix_volatile_state));
+       }
+
+       is_zero_matrix = true;
+       for (i = 0; i < MAX_MATRIX_KEY_COLS; i++) {
+               if (matrix_volatile_state[i] != 0) {
+                       is_zero_matrix = false;
+                       break;
+               }
+       }
+
+
+       if (is_zero_matrix) {
+               /*
+                * All keys have been released. Enable only the KDI
+                * interrupt for future key presses (clear the KDI
+                * status bit and its sync chain before that).
+                */
+               reg_val = readw(keypad->mmio_base + KPSR);
+               reg_val |= KBD_STAT_KPKD | KBD_STAT_KDSC;
+               writew(reg_val, keypad->mmio_base + KPSR);
+
+               reg_val = readw(keypad->mmio_base + KPSR);
+               reg_val |= KBD_STAT_KDIE;
+               reg_val &= ~KBD_STAT_KRIE;
+               writew(reg_val, keypad->mmio_base + KPSR);
+       } else {
+               /*
+                * Some keys are still pressed. Schedule a rescan in
+                * attempt to detect multiple key presses and enable
+                * the KRI interrupt to react quickly to key release
+                * event.
+                */
+               mod_timer(&keypad->check_matrix_timer,
+                         jiffies + msecs_to_jiffies(60));
+
+               reg_val = readw(keypad->mmio_base + KPSR);
+               reg_val |= KBD_STAT_KPKR | KBD_STAT_KRSS;
+               writew(reg_val, keypad->mmio_base + KPSR);
+
+               reg_val = readw(keypad->mmio_base + KPSR);
+               reg_val |= KBD_STAT_KRIE;
+               reg_val &= ~KBD_STAT_KDIE;
+               writew(reg_val, keypad->mmio_base + KPSR);
+       }
+}
+
+static irqreturn_t imx_keypad_irq_handler(int irq, void *dev_id)
+{
+       struct imx_keypad *keypad = dev_id;
+       unsigned short reg_val;
+
+       reg_val = readw(keypad->mmio_base + KPSR);
+
+       /* Disable both interrupt types */
+       reg_val &= ~(KBD_STAT_KRIE | KBD_STAT_KDIE);
+       /* Clear interrupts status bits */
+       reg_val |= KBD_STAT_KPKR | KBD_STAT_KPKD;
+       writew(reg_val, keypad->mmio_base + KPSR);
+
+       if (keypad->enabled) {
+               /* The matrix is supposed to be changed */
+               keypad->stable_count = 0;
+
+               /* Schedule the scanning procedure near in the future */
+               mod_timer(&keypad->check_matrix_timer,
+                         jiffies + msecs_to_jiffies(2));
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void imx_keypad_config(struct imx_keypad *keypad)
+{
+       unsigned short reg_val;
+
+       /*
+        * Include enabled rows in interrupt generation (KPCR[7:0])
+        * Configure keypad columns as open-drain (KPCR[15:8])
+        */
+       reg_val = readw(keypad->mmio_base + KPCR);
+       reg_val |= keypad->rows_en_mask & 0xff;         /* rows */
+       reg_val |= (keypad->cols_en_mask & 0xff) << 8;  /* cols */
+       writew(reg_val, keypad->mmio_base + KPCR);
+
+       /* Write 0's to KPDR[15:8] (Colums) */
+       reg_val = readw(keypad->mmio_base + KPDR);
+       reg_val &= 0x00ff;
+       writew(reg_val, keypad->mmio_base + KPDR);
+
+       /* Configure columns as output, rows as input (KDDR[15:0]) */
+       writew(0xff00, keypad->mmio_base + KDDR);
+
+       /*
+        * Clear Key Depress and Key Release status bit.
+        * Clear both synchronizer chain.
+        */
+       reg_val = readw(keypad->mmio_base + KPSR);
+       reg_val |= KBD_STAT_KPKR | KBD_STAT_KPKD |
+                  KBD_STAT_KDSC | KBD_STAT_KRSS;
+       writew(reg_val, keypad->mmio_base + KPSR);
+
+       /* Enable KDI and disable KRI (avoid false release events). */
+       reg_val |= KBD_STAT_KDIE;
+       reg_val &= ~KBD_STAT_KRIE;
+       writew(reg_val, keypad->mmio_base + KPSR);
+}
+
+static void imx_keypad_inhibit(struct imx_keypad *keypad)
+{
+       unsigned short reg_val;
+
+       /* Inhibit KDI and KRI interrupts. */
+       reg_val = readw(keypad->mmio_base + KPSR);
+       reg_val &= ~(KBD_STAT_KRIE | KBD_STAT_KDIE);
+       writew(reg_val, keypad->mmio_base + KPSR);
+
+       /* Colums as open drain and disable all rows */
+       writew(0xff00, keypad->mmio_base + KPCR);
+}
+
+static void imx_keypad_close(struct input_dev *dev)
+{
+       struct imx_keypad *keypad = input_get_drvdata(dev);
+
+       dev_dbg(&dev->dev, ">%s\n", __func__);
+
+       /* Mark keypad as being inactive */
+       keypad->enabled = false;
+       synchronize_irq(keypad->irq);
+       del_timer_sync(&keypad->check_matrix_timer);
+
+       imx_keypad_inhibit(keypad);
+
+       /* Disable clock unit */
+       clk_disable(keypad->clk);
+}
+
+static int imx_keypad_open(struct input_dev *dev)
+{
+       struct imx_keypad *keypad = input_get_drvdata(dev);
+
+       dev_dbg(&dev->dev, ">%s\n", __func__);
+
+       /* We became active from now */
+       keypad->enabled = true;
+
+       /* Enable the kpp clock */
+       clk_enable(keypad->clk);
+       imx_keypad_config(keypad);
+
+       /* Sanity control, not all the rows must be actived now. */
+       if ((readw(keypad->mmio_base + KPDR) & keypad->rows_en_mask) == 0) {
+               dev_err(&dev->dev,
+                       "too many keys pressed, control pins initialisation\n");
+               goto open_err;
+       }
+
+       return 0;
+
+open_err:
+       imx_keypad_close(dev);
+       return -EIO;
+}
+
+static int __devinit imx_keypad_probe(struct platform_device *pdev)
+{
+       const struct matrix_keymap_data *keymap_data = pdev->dev.platform_data;
+       struct imx_keypad *keypad;
+       struct input_dev *input_dev;
+       struct resource *res;
+       int irq, error, i;
+
+       if (keymap_data == NULL) {
+               dev_err(&pdev->dev, "no keymap defined\n");
+               return -EINVAL;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "no irq defined in platform data\n");
+               return -EINVAL;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "no I/O memory defined in platform data\n");
+               return -EINVAL;
+       }
+
+       res = request_mem_region(res->start, resource_size(res), pdev->name);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "failed to request I/O memory\n");
+               return -EBUSY;
+       }
+
+       input_dev = input_allocate_device();
+       if (!input_dev) {
+               dev_err(&pdev->dev, "failed to allocate the input device\n");
+               error = -ENOMEM;
+               goto failed_rel_mem;
+       }
+
+       keypad = kzalloc(sizeof(struct imx_keypad), GFP_KERNEL);
+       if (!keypad) {
+               dev_err(&pdev->dev, "not enough memory for driver data\n");
+               error = -ENOMEM;
+               goto failed_free_input;
+       }
+
+       keypad->input_dev = input_dev;
+       keypad->irq = irq;
+       keypad->stable_count = 0;
+
+       setup_timer(&keypad->check_matrix_timer,
+                   imx_keypad_check_for_events, (unsigned long) keypad);
+
+       keypad->mmio_base = ioremap(res->start, resource_size(res));
+       if (keypad->mmio_base == NULL) {
+               dev_err(&pdev->dev, "failed to remap I/O memory\n");
+               error = -ENOMEM;
+               goto failed_free_priv;
+       }
+
+       keypad->clk = clk_get(&pdev->dev, "kpp");
+       if (IS_ERR(keypad->clk)) {
+               dev_err(&pdev->dev, "failed to get keypad clock\n");
+               error = PTR_ERR(keypad->clk);
+               goto failed_unmap;
+       }
+
+       /* Search for rows and cols enabled */
+       for (i = 0; i < keymap_data->keymap_size; i++) {
+               keypad->rows_en_mask |= 1 << KEY_ROW(keymap_data->keymap[i]);
+               keypad->cols_en_mask |= 1 << KEY_COL(keymap_data->keymap[i]);
+       }
+
+       if (keypad->rows_en_mask > ((1 << MAX_MATRIX_KEY_ROWS) - 1) ||
+          keypad->cols_en_mask > ((1 << MAX_MATRIX_KEY_COLS) - 1)) {
+               dev_err(&pdev->dev,
+                       "invalid key data (too many rows or colums)\n");
+               error = -EINVAL;
+               goto failed_clock_put;
+       }
+       dev_dbg(&pdev->dev, "enabled rows mask: %x\n", keypad->rows_en_mask);
+       dev_dbg(&pdev->dev, "enabled cols mask: %x\n", keypad->cols_en_mask);
+
+       /* Init the Input device */
+       input_dev->name = pdev->name;
+       input_dev->id.bustype = BUS_HOST;
+       input_dev->dev.parent = &pdev->dev;
+       input_dev->open = imx_keypad_open;
+       input_dev->close = imx_keypad_close;
+       input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+       input_dev->keycode = keypad->keycodes;
+       input_dev->keycodesize = sizeof(keypad->keycodes[0]);
+       input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
+
+       matrix_keypad_build_keymap(keymap_data, MATRIX_ROW_SHIFT,
+                               keypad->keycodes, input_dev->keybit);
+
+       input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+       input_set_drvdata(input_dev, keypad);
+
+       /* Ensure that the keypad will stay dormant until opened */
+       imx_keypad_inhibit(keypad);
+
+       error = request_irq(irq, imx_keypad_irq_handler, IRQF_DISABLED,
+                           pdev->name, keypad);
+       if (error) {
+               dev_err(&pdev->dev, "failed to request IRQ\n");
+               goto failed_clock_put;
+       }
+
+       /* Register the input device */
+       error = input_register_device(input_dev);
+       if (error) {
+               dev_err(&pdev->dev, "failed to register input device\n");
+               goto failed_free_irq;
+       }
+
+       platform_set_drvdata(pdev, keypad);
+       device_init_wakeup(&pdev->dev, 1);
+
+       return 0;
+
+failed_free_irq:
+       free_irq(irq, pdev);
+failed_clock_put:
+       clk_put(keypad->clk);
+failed_unmap:
+       iounmap(keypad->mmio_base);
+failed_free_priv:
+       kfree(keypad);
+failed_free_input:
+       input_free_device(input_dev);
+failed_rel_mem:
+       release_mem_region(res->start, resource_size(res));
+       return error;
+}
+
+static int __devexit imx_keypad_remove(struct platform_device *pdev)
+{
+       struct imx_keypad *keypad = platform_get_drvdata(pdev);
+       struct resource *res;
+
+       dev_dbg(&pdev->dev, ">%s\n", __func__);
+
+       platform_set_drvdata(pdev, NULL);
+
+       input_unregister_device(keypad->input_dev);
+
+       free_irq(keypad->irq, keypad);
+       clk_put(keypad->clk);
+
+       iounmap(keypad->mmio_base);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(res->start, resource_size(res));
+
+       kfree(keypad);
+
+       return 0;
+}
+
+static struct platform_driver imx_keypad_driver = {
+       .driver         = {
+               .name   = "imx-keypad",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = imx_keypad_probe,
+       .remove         = __devexit_p(imx_keypad_remove),
+};
+
+static int __init imx_keypad_init(void)
+{
+       return platform_driver_register(&imx_keypad_driver);
+}
+
+static void __exit imx_keypad_exit(void)
+{
+       platform_driver_unregister(&imx_keypad_driver);
+}
+
+module_init(imx_keypad_init);
+module_exit(imx_keypad_exit);
+
+MODULE_AUTHOR("Alberto Panizzo <maramaopercheseimorto@gmail.com>");
+MODULE_DESCRIPTION("IMX Keypad Port Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:imx-keypad");
index 191cc51d6cf8c5609689f6990d847f3820a77b3f..31f30087b591866c9e81af4401d0a3feeaae359e 100644 (file)
@@ -362,7 +362,7 @@ static int __devexit qt2160_remove(struct i2c_client *client)
        return 0;
 }
 
-static struct i2c_device_id qt2160_idtable[] = {
+static const struct i2c_device_id qt2160_idtable[] = {
        { "qt2160", 0, },
        { }
 };
index 8e9380bfed4097fcdc283cfc7c3532ed0e911318..854e2035cd6e66108fb14f57ee7038991d5106fc 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/input.h>
 #include <linux/input/sh_keysc.h>
+#include <linux/bitmap.h>
 #include <linux/clk.h>
 #include <linux/io.h>
 
-#define KYCR1_OFFS   0x00
-#define KYCR2_OFFS   0x04
-#define KYINDR_OFFS  0x08
-#define KYOUTDR_OFFS 0x0c
-
-#define KYCR2_IRQ_LEVEL    0x10
-#define KYCR2_IRQ_DISABLED 0x00
-
 static const struct {
        unsigned char kymd, keyout, keyin;
 } sh_keysc_mode[] = {
        [SH_KEYSC_MODE_1] = { 0, 6, 5 },
        [SH_KEYSC_MODE_2] = { 1, 5, 6 },
        [SH_KEYSC_MODE_3] = { 2, 4, 7 },
+       [SH_KEYSC_MODE_4] = { 3, 6, 6 },
+       [SH_KEYSC_MODE_5] = { 4, 6, 7 },
+       [SH_KEYSC_MODE_6] = { 5, 7, 7 },
 };
 
 struct sh_keysc_priv {
        void __iomem *iomem_base;
        struct clk *clk;
-       unsigned long last_keys;
+       DECLARE_BITMAP(last_keys, SH_KEYSC_MAXKEYS);
        struct input_dev *input;
        struct sh_keysc_info pdata;
 };
 
+#define KYCR1 0
+#define KYCR2 1
+#define KYINDR 2
+#define KYOUTDR 3
+
+#define KYCR2_IRQ_LEVEL    0x10
+#define KYCR2_IRQ_DISABLED 0x00
+
+static unsigned long sh_keysc_read(struct sh_keysc_priv *p, int reg_nr)
+{
+       return ioread16(p->iomem_base + (reg_nr << 2));
+}
+
+static void sh_keysc_write(struct sh_keysc_priv *p, int reg_nr,
+                          unsigned long value)
+{
+       iowrite16(value, p->iomem_base + (reg_nr << 2));
+}
+
+static void sh_keysc_level_mode(struct sh_keysc_priv *p,
+                               unsigned long keys_set)
+{
+       struct sh_keysc_info *pdata = &p->pdata;
+
+       sh_keysc_write(p, KYOUTDR, 0);
+       sh_keysc_write(p, KYCR2, KYCR2_IRQ_LEVEL | (keys_set << 8));
+
+       if (pdata->kycr2_delay)
+               udelay(pdata->kycr2_delay);
+}
+
+static void sh_keysc_map_dbg(struct device *dev, unsigned long *map,
+                            const char *str)
+{
+       int k;
+
+       for (k = 0; k < BITS_TO_LONGS(SH_KEYSC_MAXKEYS); k++)
+               dev_dbg(dev, "%s[%d] 0x%lx\n", str, k, map[k]);
+}
+
 static irqreturn_t sh_keysc_isr(int irq, void *dev_id)
 {
        struct platform_device *pdev = dev_id;
        struct sh_keysc_priv *priv = platform_get_drvdata(pdev);
        struct sh_keysc_info *pdata = &priv->pdata;
-       unsigned long keys, keys1, keys0, mask;
+       int keyout_nr = sh_keysc_mode[pdata->mode].keyout;
+       int keyin_nr = sh_keysc_mode[pdata->mode].keyin;
+       DECLARE_BITMAP(keys, SH_KEYSC_MAXKEYS);
+       DECLARE_BITMAP(keys0, SH_KEYSC_MAXKEYS);
+       DECLARE_BITMAP(keys1, SH_KEYSC_MAXKEYS);
        unsigned char keyin_set, tmp;
-       int i, k;
+       int i, k, n;
 
        dev_dbg(&pdev->dev, "isr!\n");
 
-       keys1 = ~0;
-       keys0 = 0;
+       bitmap_fill(keys1, SH_KEYSC_MAXKEYS);
+       bitmap_zero(keys0, SH_KEYSC_MAXKEYS);
 
        do {
-               keys = 0;
+               bitmap_zero(keys, SH_KEYSC_MAXKEYS);
                keyin_set = 0;
 
-               iowrite16(KYCR2_IRQ_DISABLED, priv->iomem_base + KYCR2_OFFS);
+               sh_keysc_write(priv, KYCR2, KYCR2_IRQ_DISABLED);
+
+               for (i = 0; i < keyout_nr; i++) {
+                       n = keyin_nr * i;
 
-               for (i = 0; i < sh_keysc_mode[pdata->mode].keyout; i++) {
-                       iowrite16(0xfff ^ (3 << (i * 2)),
-                                 priv->iomem_base + KYOUTDR_OFFS);
+                       /* drive one KEYOUT pin low, read KEYIN pins */
+                       sh_keysc_write(priv, KYOUTDR, 0xffff ^ (3 << (i * 2)));
                        udelay(pdata->delay);
-                       tmp = ioread16(priv->iomem_base + KYINDR_OFFS);
-                       keys |= tmp << (sh_keysc_mode[pdata->mode].keyin * i);
-                       tmp ^= (1 << sh_keysc_mode[pdata->mode].keyin) - 1;
-                       keyin_set |= tmp;
-               }
+                       tmp = sh_keysc_read(priv, KYINDR);
 
-               iowrite16(0, priv->iomem_base + KYOUTDR_OFFS);
-               iowrite16(KYCR2_IRQ_LEVEL | (keyin_set << 8),
-                         priv->iomem_base + KYCR2_OFFS);
+                       /* set bit if key press has been detected */
+                       for (k = 0; k < keyin_nr; k++) {
+                               if (tmp & (1 << k))
+                                       __set_bit(n + k, keys);
+                       }
 
-               if (pdata->kycr2_delay)
-                       udelay(pdata->kycr2_delay);
+                       /* keep track of which KEYIN bits that have been set */
+                       keyin_set |= tmp ^ ((1 << keyin_nr) - 1);
+               }
 
-               keys ^= ~0;
-               keys &= (1 << (sh_keysc_mode[pdata->mode].keyin *
-                              sh_keysc_mode[pdata->mode].keyout)) - 1;
-               keys1 &= keys;
-               keys0 |= keys;
+               sh_keysc_level_mode(priv, keyin_set);
 
-               dev_dbg(&pdev->dev, "keys 0x%08lx\n", keys);
+               bitmap_complement(keys, keys, SH_KEYSC_MAXKEYS);
+               bitmap_and(keys1, keys1, keys, SH_KEYSC_MAXKEYS);
+               bitmap_or(keys0, keys0, keys, SH_KEYSC_MAXKEYS);
 
-       } while (ioread16(priv->iomem_base + KYCR2_OFFS) & 0x01);
+               sh_keysc_map_dbg(&pdev->dev, keys, "keys");
 
-       dev_dbg(&pdev->dev, "last_keys 0x%08lx keys0 0x%08lx keys1 0x%08lx\n",
-               priv->last_keys, keys0, keys1);
+       } while (sh_keysc_read(priv, KYCR2) & 0x01);
+
+       sh_keysc_map_dbg(&pdev->dev, priv->last_keys, "last_keys");
+       sh_keysc_map_dbg(&pdev->dev, keys0, "keys0");
+       sh_keysc_map_dbg(&pdev->dev, keys1, "keys1");
 
        for (i = 0; i < SH_KEYSC_MAXKEYS; i++) {
                k = pdata->keycodes[i];
                if (!k)
                        continue;
 
-               mask = 1 << i;
-
-               if (!((priv->last_keys ^ keys0) & mask))
+               if (test_bit(i, keys0) == test_bit(i, priv->last_keys))
                        continue;
 
-               if ((keys1 | keys0) & mask) {
+               if (test_bit(i, keys1) || test_bit(i, keys0)) {
                        input_event(priv->input, EV_KEY, k, 1);
-                       priv->last_keys |= mask;
+                       __set_bit(i, priv->last_keys);
                }
 
-               if (!(keys1 & mask)) {
+               if (!test_bit(i, keys1)) {
                        input_event(priv->input, EV_KEY, k, 0);
-                       priv->last_keys &= ~mask;
+                       __clear_bit(i, priv->last_keys);
                }
 
        }
@@ -122,8 +162,6 @@ static irqreturn_t sh_keysc_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-#define res_size(res) ((res)->end - (res)->start + 1)
-
 static int __devinit sh_keysc_probe(struct platform_device *pdev)
 {
        struct sh_keysc_priv *priv;
@@ -164,7 +202,7 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
        memcpy(&priv->pdata, pdev->dev.platform_data, sizeof(priv->pdata));
        pdata = &priv->pdata;
 
-       priv->iomem_base = ioremap_nocache(res->start, res_size(res));
+       priv->iomem_base = ioremap_nocache(res->start, resource_size(res));
        if (priv->iomem_base == NULL) {
                dev_err(&pdev->dev, "failed to remap I/O memory\n");
                error = -ENXIO;
@@ -220,10 +258,9 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
 
        clk_enable(priv->clk);
 
-       iowrite16((sh_keysc_mode[pdata->mode].kymd << 8) |
-                 pdata->scan_timing, priv->iomem_base + KYCR1_OFFS);
-       iowrite16(0, priv->iomem_base + KYOUTDR_OFFS);
-       iowrite16(KYCR2_IRQ_LEVEL, priv->iomem_base + KYCR2_OFFS);
+       sh_keysc_write(priv, KYCR1, (sh_keysc_mode[pdata->mode].kymd << 8) |
+                      pdata->scan_timing);
+       sh_keysc_level_mode(priv, 0);
 
        device_init_wakeup(&pdev->dev, 1);
 
@@ -248,7 +285,7 @@ static int __devexit sh_keysc_remove(struct platform_device *pdev)
 {
        struct sh_keysc_priv *priv = platform_get_drvdata(pdev);
 
-       iowrite16(KYCR2_IRQ_DISABLED, priv->iomem_base + KYCR2_OFFS);
+       sh_keysc_write(priv, KYCR2, KYCR2_IRQ_DISABLED);
 
        input_unregister_device(priv->input);
        free_irq(platform_get_irq(pdev, 0), pdev);
@@ -270,7 +307,7 @@ static int sh_keysc_suspend(struct device *dev)
        int irq = platform_get_irq(pdev, 0);
        unsigned short value;
 
-       value = ioread16(priv->iomem_base + KYCR1_OFFS);
+       value = sh_keysc_read(priv, KYCR1);
 
        if (device_may_wakeup(dev)) {
                value |= 0x80;
@@ -279,7 +316,7 @@ static int sh_keysc_suspend(struct device *dev)
                value &= ~0x80;
        }
 
-       iowrite16(value, priv->iomem_base + KYCR1_OFFS);
+       sh_keysc_write(priv, KYCR1, value);
 
        return 0;
 }
index 71b82434264d1c3efde2a1f0f0bc187b3ead3b5e..a8d2b8db4e359fbe521cce279909527cea4d984e 100644 (file)
@@ -149,7 +149,7 @@ static void apanel_shutdown(struct i2c_client *client)
        apanel_remove(client);
 }
 
-static struct i2c_device_id apanel_id[] = {
+static const struct i2c_device_id apanel_id[] = {
        { "fujitsu_apanel", 0 },
        { }
 };
index 1b871917340addb3b7d0d992e366b075b615f90f..dfaa9a045ed8a9378ad74030f0bc87dfd5dc8f2e 100644 (file)
@@ -47,7 +47,7 @@ static acpi_status acpi_atlas_button_setup(acpi_handle region_handle,
 
 static acpi_status acpi_atlas_button_handler(u32 function,
                      acpi_physical_address address,
-                     u32 bit_width, acpi_integer *value,
+                     u32 bit_width, u64 *value,
                      void *handler_context, void *region_context)
 {
        acpi_status status;
index 3b9f588fc74746e5bfb5179418e414d1e8a8921e..4ae07935985e744f2987246ff04435034b81b5c8 100644 (file)
@@ -152,6 +152,13 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)
                goto exit_unregister_input;
        }
 
+       err = gpio_direction_input(pdata->gpio_a);
+       if (err) {
+               dev_err(&pdev->dev, "unable to set GPIO %d for input\n",
+                       pdata->gpio_a);
+               goto exit_unregister_input;
+       }
+
        err = gpio_request(pdata->gpio_b, DRV_NAME);
        if (err) {
                dev_err(&pdev->dev, "unable to request GPIO %d\n",
@@ -159,6 +166,13 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)
                goto exit_free_gpio_a;
        }
 
+       err = gpio_direction_input(pdata->gpio_b);
+       if (err) {
+               dev_err(&pdev->dev, "unable to set GPIO %d for input\n",
+                       pdata->gpio_b);
+               goto exit_free_gpio_a;
+       }
+
        /* request the IRQs */
        err = request_irq(encoder->irq_a, &rotary_encoder_irq,
                          IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_LOWEDGE,
index d3f57245420a008a412afa9b55dd4bd8f015ce8d..1477466076ad1764989f82387cc737fd453181ab 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/fs.h>
 #include <linux/miscdevice.h>
 #include <linux/uinput.h>
@@ -284,7 +283,6 @@ static int uinput_open(struct inode *inode, struct file *file)
        if (!newdev)
                return -ENOMEM;
 
-       lock_kernel();
        mutex_init(&newdev->mutex);
        spin_lock_init(&newdev->requests_lock);
        init_waitqueue_head(&newdev->requests_waitq);
@@ -292,7 +290,7 @@ static int uinput_open(struct inode *inode, struct file *file)
        newdev->state = UIST_NEW_DEVICE;
 
        file->private_data = newdev;
-       unlock_kernel();
+       nonseekable_open(inode, file);
 
        return 0;
 }
index c8f5a9a3fa140d73218c7e4ce6a162da8287500f..cbec3dfdd42b5373de0865edfb1a49c4440468bb 100644 (file)
@@ -538,6 +538,7 @@ wbcir_reset_irdata(struct wbcir_data *data)
        data->irdata_count = 0;
        data->irdata_off = 0;
        data->irdata_error = 0;
+       data->idle_count = 0;
 }
 
 /* Adds one bit of irdata */
@@ -1006,7 +1007,6 @@ wbcir_irq_handler(int irqno, void *cookie)
                }
 
                wbcir_reset_irdata(data);
-               data->idle_count = 0;
        }
 
 out:
@@ -1018,7 +1018,7 @@ out:
 
 /*****************************************************************************
  *
- * SUSPEND/RESUME FUNCTIONS
+ * SETUP/INIT/SUSPEND/RESUME FUNCTIONS
  *
  *****************************************************************************/
 
@@ -1197,7 +1197,16 @@ finish:
        }
 
        /* Disable interrupts */
+       wbcir_select_bank(data, WBCIR_BANK_0);
        outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER);
+
+       /*
+        * ACPI will set the HW disable bit for SP3 which means that the
+        * output signals are left in an undefined state which may cause
+        * spurious interrupts which we need to ignore until the hardware
+        * is reinitialized.
+        */
+       disable_irq(data->irq);
 }
 
 static int
@@ -1207,37 +1216,15 @@ wbcir_suspend(struct pnp_dev *device, pm_message_t state)
        return 0;
 }
 
-static int
-wbcir_resume(struct pnp_dev *device)
-{
-       struct wbcir_data *data = pnp_get_drvdata(device);
-
-       /* Clear BUFF_EN, Clear END_EN, Clear MATCH_EN */
-       wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x00, 0x07);
-
-       /* Clear CEIR_EN */
-       wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, 0x00, 0x01);
-
-       /* Enable interrupts */
-       wbcir_reset_irdata(data);
-       outb(WBCIR_IRQ_RX | WBCIR_IRQ_ERR, data->sbase + WBCIR_REG_SP3_IER);
-
-       return 0;
-}
-
-
-
-/*****************************************************************************
- *
- * SETUP/INIT FUNCTIONS
- *
- *****************************************************************************/
-
 static void
-wbcir_cfg_ceir(struct wbcir_data *data)
+wbcir_init_hw(struct wbcir_data *data)
 {
        u8 tmp;
 
+       /* Disable interrupts */
+       wbcir_select_bank(data, WBCIR_BANK_0);
+       outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER);
+
        /* Set PROT_SEL, RX_INV, Clear CEIR_EN (needed for the led) */
        tmp = protocol << 4;
        if (invert)
@@ -1264,6 +1251,93 @@ wbcir_cfg_ceir(struct wbcir_data *data)
         * set SP3_IRRX_SW to binary 01, helpfully not documented
         */
        outb(0x10, data->ebase + WBCIR_REG_ECEIR_CTS);
+
+       /* Enable extended mode */
+       wbcir_select_bank(data, WBCIR_BANK_2);
+       outb(WBCIR_EXT_ENABLE, data->sbase + WBCIR_REG_SP3_EXCR1);
+
+       /*
+        * Configure baud generator, IR data will be sampled at
+        * a bitrate of: (24Mhz * prescaler) / (divisor * 16).
+        *
+        * The ECIR registers include a flag to change the
+        * 24Mhz clock freq to 48Mhz.
+        *
+        * It's not documented in the specs, but fifo levels
+        * other than 16 seems to be unsupported.
+        */
+
+       /* prescaler 1.0, tx/rx fifo lvl 16 */
+       outb(0x30, data->sbase + WBCIR_REG_SP3_EXCR2);
+
+       /* Set baud divisor to generate one byte per bit/cell */
+       switch (protocol) {
+       case IR_PROTOCOL_RC5:
+               outb(0xA7, data->sbase + WBCIR_REG_SP3_BGDL);
+               break;
+       case IR_PROTOCOL_RC6:
+               outb(0x53, data->sbase + WBCIR_REG_SP3_BGDL);
+               break;
+       case IR_PROTOCOL_NEC:
+               outb(0x69, data->sbase + WBCIR_REG_SP3_BGDL);
+               break;
+       }
+       outb(0x00, data->sbase + WBCIR_REG_SP3_BGDH);
+
+       /* Set CEIR mode */
+       wbcir_select_bank(data, WBCIR_BANK_0);
+       outb(0xC0, data->sbase + WBCIR_REG_SP3_MCR);
+       inb(data->sbase + WBCIR_REG_SP3_LSR); /* Clear LSR */
+       inb(data->sbase + WBCIR_REG_SP3_MSR); /* Clear MSR */
+
+       /* Disable RX demod, run-length encoding/decoding, set freq span */
+       wbcir_select_bank(data, WBCIR_BANK_7);
+       outb(0x10, data->sbase + WBCIR_REG_SP3_RCCFG);
+
+       /* Disable timer */
+       wbcir_select_bank(data, WBCIR_BANK_4);
+       outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR1);
+
+       /* Enable MSR interrupt, Clear AUX_IRX */
+       wbcir_select_bank(data, WBCIR_BANK_5);
+       outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR2);
+
+       /* Disable CRC */
+       wbcir_select_bank(data, WBCIR_BANK_6);
+       outb(0x20, data->sbase + WBCIR_REG_SP3_IRCR3);
+
+       /* Set RX/TX (de)modulation freq, not really used */
+       wbcir_select_bank(data, WBCIR_BANK_7);
+       outb(0xF2, data->sbase + WBCIR_REG_SP3_IRRXDC);
+       outb(0x69, data->sbase + WBCIR_REG_SP3_IRTXMC);
+
+       /* Set invert and pin direction */
+       if (invert)
+               outb(0x10, data->sbase + WBCIR_REG_SP3_IRCFG4);
+       else
+               outb(0x00, data->sbase + WBCIR_REG_SP3_IRCFG4);
+
+       /* Set FIFO thresholds (RX = 8, TX = 3), reset RX/TX */
+       wbcir_select_bank(data, WBCIR_BANK_0);
+       outb(0x97, data->sbase + WBCIR_REG_SP3_FCR);
+
+       /* Clear AUX status bits */
+       outb(0xE0, data->sbase + WBCIR_REG_SP3_ASCR);
+
+       /* Enable interrupts */
+       wbcir_reset_irdata(data);
+       outb(WBCIR_IRQ_RX | WBCIR_IRQ_ERR, data->sbase + WBCIR_REG_SP3_IER);
+}
+
+static int
+wbcir_resume(struct pnp_dev *device)
+{
+       struct wbcir_data *data = pnp_get_drvdata(device);
+
+       wbcir_init_hw(data);
+       enable_irq(data->irq);
+
+       return 0;
 }
 
 static int __devinit
@@ -1393,86 +1467,7 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
 
        device_init_wakeup(&device->dev, 1);
 
-       wbcir_cfg_ceir(data);
-
-       /* Disable interrupts */
-       wbcir_select_bank(data, WBCIR_BANK_0);
-       outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER);
-
-       /* Enable extended mode */
-       wbcir_select_bank(data, WBCIR_BANK_2);
-       outb(WBCIR_EXT_ENABLE, data->sbase + WBCIR_REG_SP3_EXCR1);
-
-       /*
-        * Configure baud generator, IR data will be sampled at
-        * a bitrate of: (24Mhz * prescaler) / (divisor * 16).
-        *
-        * The ECIR registers include a flag to change the
-        * 24Mhz clock freq to 48Mhz.
-        *
-        * It's not documented in the specs, but fifo levels
-        * other than 16 seems to be unsupported.
-        */
-
-       /* prescaler 1.0, tx/rx fifo lvl 16 */
-       outb(0x30, data->sbase + WBCIR_REG_SP3_EXCR2);
-
-       /* Set baud divisor to generate one byte per bit/cell */
-       switch (protocol) {
-       case IR_PROTOCOL_RC5:
-               outb(0xA7, data->sbase + WBCIR_REG_SP3_BGDL);
-               break;
-       case IR_PROTOCOL_RC6:
-               outb(0x53, data->sbase + WBCIR_REG_SP3_BGDL);
-               break;
-       case IR_PROTOCOL_NEC:
-               outb(0x69, data->sbase + WBCIR_REG_SP3_BGDL);
-               break;
-       }
-       outb(0x00, data->sbase + WBCIR_REG_SP3_BGDH);
-
-       /* Set CEIR mode */
-       wbcir_select_bank(data, WBCIR_BANK_0);
-       outb(0xC0, data->sbase + WBCIR_REG_SP3_MCR);
-       inb(data->sbase + WBCIR_REG_SP3_LSR); /* Clear LSR */
-       inb(data->sbase + WBCIR_REG_SP3_MSR); /* Clear MSR */
-
-       /* Disable RX demod, run-length encoding/decoding, set freq span */
-       wbcir_select_bank(data, WBCIR_BANK_7);
-       outb(0x10, data->sbase + WBCIR_REG_SP3_RCCFG);
-
-       /* Disable timer */
-       wbcir_select_bank(data, WBCIR_BANK_4);
-       outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR1);
-
-       /* Enable MSR interrupt, Clear AUX_IRX */
-       wbcir_select_bank(data, WBCIR_BANK_5);
-       outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR2);
-
-       /* Disable CRC */
-       wbcir_select_bank(data, WBCIR_BANK_6);
-       outb(0x20, data->sbase + WBCIR_REG_SP3_IRCR3);
-
-       /* Set RX/TX (de)modulation freq, not really used */
-       wbcir_select_bank(data, WBCIR_BANK_7);
-       outb(0xF2, data->sbase + WBCIR_REG_SP3_IRRXDC);
-       outb(0x69, data->sbase + WBCIR_REG_SP3_IRTXMC);
-
-       /* Set invert and pin direction */
-       if (invert)
-               outb(0x10, data->sbase + WBCIR_REG_SP3_IRCFG4);
-       else
-               outb(0x00, data->sbase + WBCIR_REG_SP3_IRCFG4);
-
-       /* Set FIFO thresholds (RX = 8, TX = 3), reset RX/TX */
-       wbcir_select_bank(data, WBCIR_BANK_0);
-       outb(0x97, data->sbase + WBCIR_REG_SP3_FCR);
-
-       /* Clear AUX status bits */
-       outb(0xE0, data->sbase + WBCIR_REG_SP3_ASCR);
-
-       /* Enable interrupts */
-       outb(WBCIR_IRQ_RX | WBCIR_IRQ_ERR, data->sbase + WBCIR_REG_SP3_IER);
+       wbcir_init_hw(data);
 
        return 0;
 
index 90be30e9355606cbc0e50971fc4381c5b429952e..9169d1591c1fea50c854c82a129bff8663d2fe12 100644 (file)
@@ -68,10 +68,6 @@ module_param(post_interrupt_delay, int, 0644);
 MODULE_PARM_DESC(post_interrupt_delay,
        "delay (ms) before recal after recal interrupt detected");
 
-static int autorecal = 1;
-module_param(autorecal, int, 0644);
-MODULE_PARM_DESC(autorecal, "enable recalibration in the driver");
-
 /*
  * When the touchpad gets ultra-sensitive, one can keep their finger 1/2"
  * above the pad and still have it send packets.  This causes a jump cursor
index 1dacbe0d934832e54cae29353fd258e9a24bb339..797314be7af2ffadc6361a44f7d87403fda419ed 100644 (file)
@@ -186,7 +186,7 @@ static void __devexit pcips2_remove(struct pci_dev *dev)
        pci_disable_device(dev);
 }
 
-static struct pci_device_id pcips2_ids[] = {
+static const struct pci_device_id pcips2_ids[] = {
        {
                .vendor         = 0x14f2,       /* MOBILITY */
                .device         = 0x0123,       /* Keyboard */
index e0f30186d513d4633649beeb9a7f73e361c7d972..c3b626e9eae7c075cd7597779ddbef4becb731f6 100644 (file)
@@ -26,6 +26,8 @@
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/stddef.h>
 #include <linux/module.h>
 #include <linux/serio.h>
@@ -119,11 +121,10 @@ static int serio_bind_driver(struct serio *serio, struct serio_driver *drv)
 
                error = device_bind_driver(&serio->dev);
                if (error) {
-                       printk(KERN_WARNING
-                               "serio: device_bind_driver() failed "
-                               "for %s (%s) and %s, error: %d\n",
-                               serio->phys, serio->name,
-                               drv->description, error);
+                       dev_warn(&serio->dev,
+                                "device_bind_driver() failed for %s (%s) and %s, error: %d\n",
+                                serio->phys, serio->name,
+                                drv->description, error);
                        serio_disconnect_driver(serio);
                        serio->dev.driver = NULL;
                        return error;
@@ -138,9 +139,9 @@ static void serio_find_driver(struct serio *serio)
 
        error = device_attach(&serio->dev);
        if (error < 0)
-               printk(KERN_WARNING
-                       "serio: device_attach() failed for %s (%s), error: %d\n",
-                       serio->phys, serio->name, error);
+               dev_warn(&serio->dev,
+                        "device_attach() failed for %s (%s), error: %d\n",
+                        serio->phys, serio->name, error);
 }
 
 
@@ -194,17 +195,14 @@ static int serio_queue_event(void *object, struct module *owner,
 
        event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC);
        if (!event) {
-               printk(KERN_ERR
-                       "serio: Not enough memory to queue event %d\n",
-                       event_type);
+               pr_err("Not enough memory to queue event %d\n", event_type);
                retval = -ENOMEM;
                goto out;
        }
 
        if (!try_module_get(owner)) {
-               printk(KERN_WARNING
-                       "serio: Can't get module reference, dropping event %d\n",
-                       event_type);
+               pr_warning("Can't get module reference, dropping event %d\n",
+                          event_type);
                kfree(event);
                retval = -EINVAL;
                goto out;
@@ -230,14 +228,12 @@ static void serio_free_event(struct serio_event *event)
 
 static void serio_remove_duplicate_events(struct serio_event *event)
 {
-       struct list_head *node, *next;
-       struct serio_event *e;
+       struct serio_event *e, *next;
        unsigned long flags;
 
        spin_lock_irqsave(&serio_event_lock, flags);
 
-       list_for_each_safe(node, next, &serio_event_list) {
-               e = list_entry(node, struct serio_event, node);
+       list_for_each_entry_safe(e, next, &serio_event_list, node) {
                if (event->object == e->object) {
                        /*
                         * If this event is of different type we should not
@@ -247,7 +243,7 @@ static void serio_remove_duplicate_events(struct serio_event *event)
                        if (event->type != e->type)
                                break;
 
-                       list_del_init(node);
+                       list_del_init(&e->node);
                        serio_free_event(e);
                }
        }
@@ -258,23 +254,18 @@ static void serio_remove_duplicate_events(struct serio_event *event)
 
 static struct serio_event *serio_get_event(void)
 {
-       struct serio_event *event;
-       struct list_head *node;
+       struct serio_event *event = NULL;
        unsigned long flags;
 
        spin_lock_irqsave(&serio_event_lock, flags);
 
-       if (list_empty(&serio_event_list)) {
-               spin_unlock_irqrestore(&serio_event_lock, flags);
-               return NULL;
+       if (!list_empty(&serio_event_list)) {
+               event = list_first_entry(&serio_event_list,
+                                        struct serio_event, node);
+               list_del_init(&event->node);
        }
 
-       node = serio_event_list.next;
-       event = list_entry(node, struct serio_event, node);
-       list_del_init(node);
-
        spin_unlock_irqrestore(&serio_event_lock, flags);
-
        return event;
 }
 
@@ -287,29 +278,27 @@ static void serio_handle_event(void)
        while ((event = serio_get_event())) {
 
                switch (event->type) {
-                       case SERIO_REGISTER_PORT:
-                               serio_add_port(event->object);
-                               break;
 
-                       case SERIO_RECONNECT_PORT:
-                               serio_reconnect_port(event->object);
-                               break;
+               case SERIO_REGISTER_PORT:
+                       serio_add_port(event->object);
+                       break;
 
-                       case SERIO_RESCAN_PORT:
-                               serio_disconnect_port(event->object);
-                               serio_find_driver(event->object);
-                               break;
+               case SERIO_RECONNECT_PORT:
+                       serio_reconnect_port(event->object);
+                       break;
 
-                       case SERIO_RECONNECT_CHAIN:
-                               serio_reconnect_chain(event->object);
-                               break;
+               case SERIO_RESCAN_PORT:
+                       serio_disconnect_port(event->object);
+                       serio_find_driver(event->object);
+                       break;
 
-                       case SERIO_ATTACH_DRIVER:
-                               serio_attach_driver(event->object);
-                               break;
+               case SERIO_RECONNECT_CHAIN:
+                       serio_reconnect_chain(event->object);
+                       break;
 
-                       default:
-                               break;
+               case SERIO_ATTACH_DRIVER:
+                       serio_attach_driver(event->object);
+                       break;
                }
 
                serio_remove_duplicate_events(event);
@@ -325,16 +314,14 @@ static void serio_handle_event(void)
  */
 static void serio_remove_pending_events(void *object)
 {
-       struct list_head *node, *next;
-       struct serio_event *event;
+       struct serio_event *event, *next;
        unsigned long flags;
 
        spin_lock_irqsave(&serio_event_lock, flags);
 
-       list_for_each_safe(node, next, &serio_event_list) {
-               event = list_entry(node, struct serio_event, node);
+       list_for_each_entry_safe(event, next, &serio_event_list, node) {
                if (event->object == object) {
-                       list_del_init(node);
+                       list_del_init(&event->node);
                        serio_free_event(event);
                }
        }
@@ -380,7 +367,6 @@ static int serio_thread(void *nothing)
                        kthread_should_stop() || !list_empty(&serio_event_list));
        } while (!kthread_should_stop());
 
-       printk(KERN_DEBUG "serio: kseriod exiting\n");
        return 0;
 }
 
@@ -445,6 +431,11 @@ static struct attribute_group serio_id_attr_group = {
        .attrs  = serio_device_id_attrs,
 };
 
+static const struct attribute_group *serio_device_attr_groups[] = {
+       &serio_id_attr_group,
+       NULL
+};
+
 static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
        struct serio *serio = to_serio_port(dev);
@@ -532,6 +523,7 @@ static void serio_init_port(struct serio *serio)
                        (long)atomic_inc_return(&serio_no) - 1);
        serio->dev.bus = &serio_bus;
        serio->dev.release = serio_release_port;
+       serio->dev.groups = serio_device_attr_groups;
        if (serio->parent) {
                serio->dev.parent = &serio->parent->dev;
                serio->depth = serio->parent->depth + 1;
@@ -555,21 +547,15 @@ static void serio_add_port(struct serio *serio)
        }
 
        list_add_tail(&serio->node, &serio_list);
+
        if (serio->start)
                serio->start(serio);
+
        error = device_add(&serio->dev);
        if (error)
-               printk(KERN_ERR
-                       "serio: device_add() failed for %s (%s), error: %d\n",
+               dev_err(&serio->dev,
+                       "device_add() failed for %s (%s), error: %d\n",
                        serio->phys, serio->name, error);
-       else {
-               serio->registered = true;
-               error = sysfs_create_group(&serio->dev.kobj, &serio_id_attr_group);
-               if (error)
-                       printk(KERN_ERR
-                               "serio: sysfs_create_group() failed for %s (%s), error: %d\n",
-                               serio->phys, serio->name, error);
-       }
 }
 
 /*
@@ -596,11 +582,8 @@ static void serio_destroy_port(struct serio *serio)
                serio->parent = NULL;
        }
 
-       if (serio->registered) {
-               sysfs_remove_group(&serio->dev.kobj, &serio_id_attr_group);
+       if (device_is_registered(&serio->dev))
                device_del(&serio->dev);
-               serio->registered = false;
-       }
 
        list_del_init(&serio->node);
        serio_remove_pending_events(serio);
@@ -798,9 +781,8 @@ static void serio_attach_driver(struct serio_driver *drv)
 
        error = driver_attach(&drv->driver);
        if (error)
-               printk(KERN_WARNING
-                       "serio: driver_attach() failed for %s with error %d\n",
-                       drv->driver.name, error);
+               pr_warning("driver_attach() failed for %s with error %d\n",
+                          drv->driver.name, error);
 }
 
 int __serio_register_driver(struct serio_driver *drv, struct module *owner, const char *mod_name)
@@ -820,8 +802,7 @@ int __serio_register_driver(struct serio_driver *drv, struct module *owner, cons
 
        error = driver_register(&drv->driver);
        if (error) {
-               printk(KERN_ERR
-                       "serio: driver_register() failed for %s, error: %d\n",
+               pr_err("driver_register() failed for %s, error: %d\n",
                        drv->driver.name, error);
                return error;
        }
@@ -987,7 +968,7 @@ irqreturn_t serio_interrupt(struct serio *serio,
 
         if (likely(serio->drv)) {
                 ret = serio->drv->interrupt(serio, data, dfl);
-       } else if (!dfl && serio->registered) {
+       } else if (!dfl && device_is_registered(&serio->dev)) {
                serio_rescan(serio);
                ret = IRQ_HANDLED;
        }
@@ -1018,7 +999,7 @@ static int __init serio_init(void)
 
        error = bus_register(&serio_bus);
        if (error) {
-               printk(KERN_ERR "serio: failed to register serio bus, error: %d\n", error);
+               pr_err("Failed to register serio bus, error: %d\n", error);
                return error;
        }
 
@@ -1026,7 +1007,7 @@ static int __init serio_init(void)
        if (IS_ERR(serio_task)) {
                bus_unregister(&serio_bus);
                error = PTR_ERR(serio_task);
-               printk(KERN_ERR "serio: Failed to start kseriod, error: %d\n", error);
+               pr_err("Failed to start kseriod, error: %d\n", error);
                return error;
        }
 
index ebb22f88c8426bdd3cebff9e2f822d0b7412ade7..8298e1f68234df7cbd33afbc4d452595155530c0 100644 (file)
@@ -270,7 +270,7 @@ static int __devinit xps2_of_probe(struct of_device *ofdev,
        drvdata->irq = r_irq.start;
 
        phys_addr = r_mem.start;
-       remap_size = r_mem.end - r_mem.start + 1;
+       remap_size = resource_size(&r_mem);
        if (!request_mem_region(phys_addr, remap_size, DRIVER_NAME)) {
                dev_err(dev, "Couldn't lock memory region at 0x%08llX\n",
                        (unsigned long long)phys_addr);
@@ -344,7 +344,7 @@ static int __devexit xps2_of_remove(struct of_device *of_dev)
        if (of_address_to_resource(of_dev->node, 0, &r_mem))
                dev_err(dev, "invalid address\n");
        else
-               release_mem_region(r_mem.start, r_mem.end - r_mem.start + 1);
+               release_mem_region(r_mem.start, resource_size(&r_mem));
 
        kfree(drvdata);
 
@@ -354,7 +354,7 @@ static int __devexit xps2_of_remove(struct of_device *of_dev)
 }
 
 /* Match table for of_platform binding */
-static struct of_device_id xps2_of_match[] __devinitdata = {
+static const struct of_device_id xps2_of_match[] __devinitconst = {
        { .compatible = "xlnx,xps-ps2-1.00.a", },
        { /* end of list */ },
 };
index 3d32d3f4e486629d653330b38aafc59fb44d1af7..866a9ee1af1ae8f6093a3108867e2b6da5deb0a9 100644 (file)
@@ -92,7 +92,7 @@ Scott Hill shill@gtcocalcomp.com
 /* DATA STRUCTURES */
 
 /* Device table */
-static struct usb_device_id gtco_usbid_table [] = {
+static const struct usb_device_id gtco_usbid_table[] = {
        { USB_DEVICE(VENDOR_ID_GTCO, PID_400) },
        { USB_DEVICE(VENDOR_ID_GTCO, PID_401) },
        { USB_DEVICE(VENDOR_ID_GTCO, PID_1000) },
index 16310f368dab0d24d3eeae9fe75e7f26d5b1135b..8fef1b689c692c0d51aff284b338684130bf28e2 100644 (file)
@@ -85,6 +85,7 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/mod_devicetable.h>
 #include <linux/init.h>
 #include <linux/usb/input.h>
 #include <asm/unaligned.h>
@@ -120,6 +121,8 @@ struct wacom_combo {
        struct urb *urb;
 };
 
+extern const struct usb_device_id wacom_ids[];
+
 extern int wacom_wac_irq(struct wacom_wac * wacom_wac, void * wcombo);
 extern void wacom_report_abs(void *wcombo, unsigned int abs_type, int abs_data);
 extern void wacom_report_rel(void *wcombo, unsigned int rel_type, int rel_data);
@@ -142,7 +145,5 @@ extern void input_dev_mo(struct input_dev *input_dev, struct wacom_wac *wacom_wa
 extern void input_dev_bee(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
 extern __u16 wacom_le16_to_cpu(unsigned char *data);
 extern __u16 wacom_be16_to_cpu(unsigned char *data);
-extern struct wacom_features *get_wacom_feature(const struct usb_device_id *id);
-extern const struct usb_device_id *get_device_table(void);
 
 #endif
index 072f33b3b2b027c52512569438376929226b5886..a1770e6feeecbce050078a8bdd6571aa9aab2018 100644 (file)
@@ -211,7 +211,8 @@ void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
        input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_RUBBER) |
                BIT_MASK(BTN_TOOL_PEN) | BIT_MASK(BTN_STYLUS) |
                BIT_MASK(BTN_TOOL_MOUSE) | BIT_MASK(BTN_STYLUS2);
-       input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0);
+       input_set_abs_params(input_dev, ABS_DISTANCE,
+                            0, wacom_wac->features.distance_max, 0, 0);
 }
 
 void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
@@ -261,7 +262,8 @@ void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
                BIT_MASK(BTN_TOOL_MOUSE) | BIT_MASK(BTN_TOOL_BRUSH) |
                BIT_MASK(BTN_TOOL_PENCIL) | BIT_MASK(BTN_TOOL_AIRBRUSH) |
                BIT_MASK(BTN_TOOL_LENS) | BIT_MASK(BTN_STYLUS2);
-       input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0);
+       input_set_abs_params(input_dev, ABS_DISTANCE,
+                            0, wacom_wac->features.distance_max, 0, 0);
        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);
@@ -282,17 +284,19 @@ void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
 
 void input_dev_tpc(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
 {
-       if (wacom_wac->features->device_type == BTN_TOOL_DOUBLETAP ||
-           wacom_wac->features->device_type == BTN_TOOL_TRIPLETAP) {
-               input_set_abs_params(input_dev, ABS_RX, 0, wacom_wac->features->x_phy, 0, 0);
-               input_set_abs_params(input_dev, ABS_RY, 0, wacom_wac->features->y_phy, 0, 0);
-               input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_DOUBLETAP);
+       struct wacom_features *features = &wacom_wac->features;
+
+       if (features->device_type == BTN_TOOL_DOUBLETAP ||
+           features->device_type == BTN_TOOL_TRIPLETAP) {
+               input_set_abs_params(input_dev, ABS_RX, 0, features->x_phy, 0, 0);
+               input_set_abs_params(input_dev, ABS_RY, 0, features->y_phy, 0, 0);
+               __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
        }
 }
 
 void input_dev_tpc2fg(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
 {
-       if (wacom_wac->features->device_type == BTN_TOOL_TRIPLETAP) {
+       if (wacom_wac->features.device_type == BTN_TOOL_TRIPLETAP) {
                input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_TRIPLETAP);
                input_dev->evbit[0] |= BIT_MASK(EV_MSC);
                input_dev->mscbit[0] |= BIT_MASK(MSC_SERIAL);
@@ -532,21 +536,38 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
        struct wacom_wac *wacom_wac;
        struct wacom_features *features;
        struct input_dev *input_dev;
-       int error = -ENOMEM;
+       int error;
+
+       if (!id->driver_info)
+               return -EINVAL;
 
        wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
        wacom_wac = kzalloc(sizeof(struct wacom_wac), GFP_KERNEL);
        input_dev = input_allocate_device();
-       if (!wacom || !input_dev || !wacom_wac)
+       if (!wacom || !input_dev || !wacom_wac) {
+               error = -ENOMEM;
                goto fail1;
+       }
 
-       wacom_wac->data = usb_buffer_alloc(dev, WACOM_PKGLEN_MAX, GFP_KERNEL, &wacom->data_dma);
-       if (!wacom_wac->data)
+       wacom_wac->features = *((struct wacom_features *)id->driver_info);
+       features = &wacom_wac->features;
+       if (features->pktlen > WACOM_PKGLEN_MAX) {
+               error = -EINVAL;
                goto fail1;
+       }
+
+       wacom_wac->data = usb_buffer_alloc(dev, WACOM_PKGLEN_MAX,
+                                          GFP_KERNEL, &wacom->data_dma);
+       if (!wacom_wac->data) {
+               error = -ENOMEM;
+               goto fail1;
+       }
 
        wacom->irq = usb_alloc_urb(0, GFP_KERNEL);
-       if (!wacom->irq)
+       if (!wacom->irq) {
+               error = -ENOMEM;
                goto fail2;
+       }
 
        wacom->usbdev = dev;
        wacom->dev = input_dev;
@@ -555,11 +576,6 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
        usb_make_path(dev, wacom->phys, sizeof(wacom->phys));
        strlcat(wacom->phys, "/input0", sizeof(wacom->phys));
 
-       wacom_wac->features = features = get_wacom_feature(id);
-       BUG_ON(features->pktlen > WACOM_PKGLEN_MAX);
-
-       input_dev->name = wacom_wac->features->name;
-       wacom->wacom_wac = wacom_wac;
        usb_to_input_id(dev, &input_dev->id);
 
        input_dev->dev.parent = &intf->dev;
@@ -576,6 +592,19 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
        if (error)
                goto fail2;
 
+       strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name));
+
+       if (features->type == TABLETPC || features->type == TABLETPC2FG) {
+               /* Append the device type to the name */
+               strlcat(wacom_wac->name,
+                       features->device_type == BTN_TOOL_PEN ?
+                               " Pen" : " Finger",
+                       sizeof(wacom_wac->name));
+       }
+
+       input_dev->name = wacom_wac->name;
+       wacom->wacom_wac = wacom_wac;
+
        input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
        input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOUCH);
 
@@ -640,7 +669,7 @@ static int wacom_suspend(struct usb_interface *intf, pm_message_t message)
 static int wacom_resume(struct usb_interface *intf)
 {
        struct wacom *wacom = usb_get_intfdata(intf);
-       struct wacom_features *features = wacom->wacom_wac->features;
+       struct wacom_features *features = &wacom->wacom_wac->features;
        int rv;
 
        mutex_lock(&wacom->lock);
@@ -663,6 +692,7 @@ static int wacom_reset_resume(struct usb_interface *intf)
 
 static struct usb_driver wacom_driver = {
        .name =         "wacom",
+       .id_table =     wacom_ids,
        .probe =        wacom_probe,
        .disconnect =   wacom_disconnect,
        .suspend =      wacom_suspend,
@@ -674,7 +704,7 @@ static struct usb_driver wacom_driver = {
 static int __init wacom_init(void)
 {
        int result;
-       wacom_driver.id_table = get_device_table();
+
        result = usb_register(&wacom_driver);
        if (result == 0)
                printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
index 1056f149fe31653d423f1da1d10c6e2f0d783d6b..3d81443e683ab4d49a107a656ac6048601825909 100644 (file)
@@ -55,6 +55,7 @@ static int wacom_penpartner_irq(struct wacom_wac *wacom, void *wcombo)
 
 static int wacom_pl_irq(struct wacom_wac *wacom, void *wcombo)
 {
+       struct wacom_features *features = &wacom->features;
        unsigned char *data = wacom->data;
        int prox, pressure;
 
@@ -68,9 +69,9 @@ static int wacom_pl_irq(struct wacom_wac *wacom, void *wcombo)
        if (prox) {
                wacom->id[0] = ERASER_DEVICE_ID;
                pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
-               if (wacom->features->pressure_max > 255)
+               if (features->pressure_max > 255)
                        pressure = (pressure << 1) | ((data[4] >> 6) & 1);
-               pressure += (wacom->features->pressure_max + 1) / 2;
+               pressure += (features->pressure_max + 1) / 2;
 
                /*
                 * if going from out of proximity into proximity select between the eraser
@@ -152,6 +153,7 @@ static int wacom_ptu_irq(struct wacom_wac *wacom, void *wcombo)
 
 static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
 {
+       struct wacom_features *features = &wacom->features;
        unsigned char *data = wacom->data;
        int x, y, rw;
        static int penData = 0;
@@ -179,8 +181,7 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
 
                        case 2: /* Mouse with wheel */
                                wacom_report_key(wcombo, BTN_MIDDLE, data[1] & 0x04);
-                               if (wacom->features->type == WACOM_G4 ||
-                                               wacom->features->type == WACOM_MO) {
+                               if (features->type == WACOM_G4 || features->type == WACOM_MO) {
                                        rw = data[7] & 0x04 ? (data[7] & 0x03)-4 : (data[7] & 0x03);
                                        wacom_report_rel(wcombo, REL_WHEEL, -rw);
                                } else
@@ -192,8 +193,7 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
                                wacom->id[0] = CURSOR_DEVICE_ID;
                                wacom_report_key(wcombo, BTN_LEFT, data[1] & 0x01);
                                wacom_report_key(wcombo, BTN_RIGHT, data[1] & 0x02);
-                               if (wacom->features->type == WACOM_G4 ||
-                                               wacom->features->type == WACOM_MO)
+                               if (features->type == WACOM_G4 || features->type == WACOM_MO)
                                        wacom_report_abs(wcombo, ABS_DISTANCE, data[6] & 0x3f);
                                else
                                        wacom_report_abs(wcombo, ABS_DISTANCE, data[7] & 0x3f);
@@ -230,7 +230,7 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
        }
 
        /* send pad data */
-       switch (wacom->features->type) {
+       switch (features->type) {
            case WACOM_G4:
                if (data[7] & 0xf8) {
                        if (penData) {
@@ -300,11 +300,12 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
 
 static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
 {
+       struct wacom_features *features = &wacom->features;
        unsigned char *data = wacom->data;
        int idx = 0;
 
        /* tool number */
-       if (wacom->features->type == INTUOS)
+       if (features->type == INTUOS)
                idx = data[1] & 0x01;
 
        /* Enter report */
@@ -402,7 +403,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
                        wacom_report_key(wcombo, BTN_STYLUS2, 0);
                        wacom_report_key(wcombo, BTN_TOUCH, 0);
                        wacom_report_abs(wcombo, ABS_WHEEL, 0);
-                       if (wacom->features->type >= INTUOS3S)
+                       if (features->type >= INTUOS3S)
                                wacom_report_abs(wcombo, ABS_Z, 0);
                }
                wacom_report_key(wcombo, wacom->tool[idx], 0);
@@ -416,13 +417,14 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
 
 static void wacom_intuos_general(struct wacom_wac *wacom, void *wcombo)
 {
+       struct wacom_features *features = &wacom->features;
        unsigned char *data = wacom->data;
        unsigned int t;
 
        /* general pen packet */
        if ((data[1] & 0xb8) == 0xa0) {
                t = (data[6] << 2) | ((data[7] >> 6) & 3);
-               if (wacom->features->type >= INTUOS4S && wacom->features->type <= INTUOS4L)
+               if (features->type >= INTUOS4S && features->type <= INTUOS4L)
                        t = (t << 1) | (data[1] & 1);
                wacom_report_abs(wcombo, ABS_PRESSURE, t);
                wacom_report_abs(wcombo, ABS_TILT_X,
@@ -446,6 +448,7 @@ static void wacom_intuos_general(struct wacom_wac *wacom, void *wcombo)
 
 static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
 {
+       struct wacom_features *features = &wacom->features;
        unsigned char *data = wacom->data;
        unsigned int t;
        int idx = 0, result;
@@ -457,7 +460,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
        }
 
        /* tool number */
-       if (wacom->features->type == INTUOS)
+       if (features->type == INTUOS)
                idx = data[1] & 0x01;
 
        /* pad packets. Works as a second tool and is always in prox */
@@ -466,7 +469,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
                if (wacom->tool[1] != BTN_TOOL_FINGER)
                        wacom->tool[1] = BTN_TOOL_FINGER;
 
-               if (wacom->features->type >= INTUOS4S && wacom->features->type <= INTUOS4L) {
+               if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
                        wacom_report_key(wcombo, BTN_0, (data[2] & 0x01));
                        wacom_report_key(wcombo, BTN_1, (data[3] & 0x01));
                        wacom_report_key(wcombo, BTN_2, (data[3] & 0x02));
@@ -480,7 +483,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
                                /* Out of proximity, clear wheel value. */
                                wacom_report_abs(wcombo, ABS_WHEEL, 0);
                        }
-                       if (wacom->features->type != INTUOS4S) {
+                       if (features->type != INTUOS4S) {
                                wacom_report_key(wcombo, BTN_7, (data[3] & 0x40));
                                wacom_report_key(wcombo, BTN_8, (data[3] & 0x80));
                        }
@@ -528,18 +531,20 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
                return 0;
 
        /* Only large Intuos support Lense Cursor */
-       if ((wacom->tool[idx] == BTN_TOOL_LENS)
-                       && ((wacom->features->type == INTUOS3)
-                       || (wacom->features->type == INTUOS3S)
-                       || (wacom->features->type == INTUOS4)
-                       || (wacom->features->type == INTUOS4S)))
+       if (wacom->tool[idx] == BTN_TOOL_LENS &&
+           (features->type == INTUOS3 ||
+            features->type == INTUOS3S ||
+            features->type == INTUOS4 ||
+            features->type == INTUOS4S)) {
+
                return 0;
+       }
 
        /* Cintiq doesn't send data when RDY bit isn't set */
-       if ((wacom->features->type == CINTIQ) && !(data[1] & 0x40))
+       if (features->type == CINTIQ && !(data[1] & 0x40))
                  return 0;
 
-       if (wacom->features->type >= INTUOS3S) {
+       if (features->type >= INTUOS3S) {
                wacom_report_abs(wcombo, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1));
                wacom_report_abs(wcombo, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1));
                wacom_report_abs(wcombo, ABS_DISTANCE, ((data[9] >> 2) & 0x3f));
@@ -557,7 +562,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
 
                if (data[1] & 0x02) {
                        /* Rotation packet */
-                       if (wacom->features->type >= INTUOS3S) {
+                       if (features->type >= INTUOS3S) {
                                /* I3 marker pen rotation */
                                t = (data[6] << 3) | ((data[7] >> 5) & 7);
                                t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
@@ -570,7 +575,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
                                        ((t - 1) / 2) : -t / 2);
                        }
 
-               } else if (!(data[1] & 0x10) && wacom->features->type < INTUOS3S) {
+               } else if (!(data[1] & 0x10) && features->type < INTUOS3S) {
                        /* 4D mouse packet */
                        wacom_report_key(wcombo, BTN_LEFT,   data[8] & 0x01);
                        wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02);
@@ -583,7 +588,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
 
                } else if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
                        /* I4 mouse */
-                       if (wacom->features->type >= INTUOS4S && wacom->features->type <= INTUOS4L) {
+                       if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
                                wacom_report_key(wcombo, BTN_LEFT,   data[6] & 0x01);
                                wacom_report_key(wcombo, BTN_MIDDLE, data[6] & 0x02);
                                wacom_report_key(wcombo, BTN_RIGHT,  data[6] & 0x04);
@@ -604,13 +609,13 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
                                                 - ((data[8] & 0x02) >> 1));
 
                                /* I3 2D mouse side buttons */
-                               if (wacom->features->type >= INTUOS3S && wacom->features->type <= INTUOS3L) {
+                               if (features->type >= INTUOS3S && features->type <= INTUOS3L) {
                                        wacom_report_key(wcombo, BTN_SIDE,   data[8] & 0x40);
                                        wacom_report_key(wcombo, BTN_EXTRA,  data[8] & 0x20);
                                }
                        }
-               } else if ((wacom->features->type < INTUOS3S || wacom->features->type == INTUOS3L ||
-                               wacom->features->type == INTUOS4L) &&
+               } else if ((features->type < INTUOS3S || features->type == INTUOS3L ||
+                               features->type == INTUOS4L) &&
                           wacom->tool[idx] == BTN_TOOL_LENS) {
                        /* Lens cursor packets */
                        wacom_report_key(wcombo, BTN_LEFT,   data[8] & 0x01);
@@ -718,6 +723,7 @@ static void wacom_tpc_touch_in(struct wacom_wac *wacom, void *wcombo)
 
 static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo)
 {
+       struct wacom_features *features = &wacom->features;
        char *data = wacom->data;
        int prox = 0, pressure, idx = -1;
        static int stylusInProx, touchInProx = 1, touchOut;
@@ -791,7 +797,7 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo)
                        wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[4]));
                        pressure = ((data[7] & 0x01) << 8) | data[6];
                        if (pressure < 0)
-                               pressure = wacom->features->pressure_max + pressure + 1;
+                               pressure = features->pressure_max + pressure + 1;
                        wacom_report_abs(wcombo, ABS_PRESSURE, pressure);
                        wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x05);
                } else {
@@ -815,7 +821,7 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo)
 
 int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo)
 {
-       switch (wacom_wac->features->type) {
+       switch (wacom_wac->features.type) {
                case PENPARTNER:
                        return wacom_penpartner_irq(wacom_wac, wcombo);
 
@@ -853,7 +859,7 @@ int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo)
 
 void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
 {
-       switch (wacom_wac->features->type) {
+       switch (wacom_wac->features.type) {
                case WACOM_MO:
                        input_dev_mo(input_dev, wacom_wac);
                case WACOM_G4:
@@ -888,7 +894,7 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w
                        /* fall through */
                case TABLETPC:
                        input_dev_tpc(input_dev, wacom_wac);
-                       if (wacom_wac->features->device_type != BTN_TOOL_PEN)
+                       if (wacom_wac->features.device_type != BTN_TOOL_PEN)
                                break;  /* no need to process stylus stuff */
 
                        /* fall through */
@@ -903,153 +909,201 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w
        return;
 }
 
-static struct wacom_features wacom_features[] = {
-       { "Wacom Penpartner",     WACOM_PKGLEN_PENPRTN,    5040,  3780,  255,  0, PENPARTNER },
-       { "Wacom Graphire",       WACOM_PKGLEN_GRAPHIRE,  10206,  7422,  511, 63, GRAPHIRE },
-       { "Wacom Graphire2 4x5",  WACOM_PKGLEN_GRAPHIRE,  10206,  7422,  511, 63, GRAPHIRE },
-       { "Wacom Graphire2 5x7",  WACOM_PKGLEN_GRAPHIRE,  13918, 10206,  511, 63, GRAPHIRE },
-       { "Wacom Graphire3",      WACOM_PKGLEN_GRAPHIRE,  10208,  7424,  511, 63, GRAPHIRE },
-       { "Wacom Graphire3 6x8",  WACOM_PKGLEN_GRAPHIRE,  16704, 12064,  511, 63, GRAPHIRE },
-       { "Wacom Graphire4 4x5",  WACOM_PKGLEN_GRAPHIRE,  10208,  7424,  511, 63, WACOM_G4 },
-       { "Wacom Graphire4 6x8",  WACOM_PKGLEN_GRAPHIRE,  16704, 12064,  511, 63, WACOM_G4 },
-       { "Wacom BambooFun 4x5",  WACOM_PKGLEN_BBFUN,     14760,  9225,  511, 63, WACOM_MO },
-       { "Wacom BambooFun 6x8",  WACOM_PKGLEN_BBFUN,     21648, 13530,  511, 63, WACOM_MO },
-       { "Wacom Bamboo1 Medium", WACOM_PKGLEN_GRAPHIRE,  16704, 12064,  511, 63, GRAPHIRE },
-       { "Wacom Volito",         WACOM_PKGLEN_GRAPHIRE,   5104,  3712,  511, 63, GRAPHIRE },
-       { "Wacom PenStation2",    WACOM_PKGLEN_GRAPHIRE,   3250,  2320,  255, 63, GRAPHIRE },
-       { "Wacom Volito2 4x5",    WACOM_PKGLEN_GRAPHIRE,   5104,  3712,  511, 63, GRAPHIRE },
-       { "Wacom Volito2 2x3",    WACOM_PKGLEN_GRAPHIRE,   3248,  2320,  511, 63, GRAPHIRE },
-       { "Wacom PenPartner2",    WACOM_PKGLEN_GRAPHIRE,   3250,  2320,  511, 63, GRAPHIRE },
-       { "Wacom Bamboo",         WACOM_PKGLEN_BBFUN,     14760,  9225,  511, 63, WACOM_MO },
-       { "Wacom Bamboo1",        WACOM_PKGLEN_GRAPHIRE,   5104,  3712,  511, 63, GRAPHIRE },
-       { "Wacom Intuos 4x5",     WACOM_PKGLEN_INTUOS,    12700, 10600, 1023, 31, INTUOS },
-       { "Wacom Intuos 6x8",     WACOM_PKGLEN_INTUOS,    20320, 16240, 1023, 31, INTUOS },
-       { "Wacom Intuos 9x12",    WACOM_PKGLEN_INTUOS,    30480, 24060, 1023, 31, INTUOS },
-       { "Wacom Intuos 12x12",   WACOM_PKGLEN_INTUOS,    30480, 31680, 1023, 31, INTUOS },
-       { "Wacom Intuos 12x18",   WACOM_PKGLEN_INTUOS,    45720, 31680, 1023, 31, INTUOS },
-       { "Wacom PL400",          WACOM_PKGLEN_GRAPHIRE,   5408,  4056,  255,  0, PL },
-       { "Wacom PL500",          WACOM_PKGLEN_GRAPHIRE,   6144,  4608,  255,  0, PL },
-       { "Wacom PL600",          WACOM_PKGLEN_GRAPHIRE,   6126,  4604,  255,  0, PL },
-       { "Wacom PL600SX",        WACOM_PKGLEN_GRAPHIRE,   6260,  5016,  255,  0, PL },
-       { "Wacom PL550",          WACOM_PKGLEN_GRAPHIRE,   6144,  4608,  511,  0, PL },
-       { "Wacom PL800",          WACOM_PKGLEN_GRAPHIRE,   7220,  5780,  511,  0, PL },
-       { "Wacom PL700",          WACOM_PKGLEN_GRAPHIRE,   6758,  5406,  511,  0, PL },
-       { "Wacom PL510",          WACOM_PKGLEN_GRAPHIRE,   6282,  4762,  511,  0, PL },
-       { "Wacom DTU710",         WACOM_PKGLEN_GRAPHIRE,  34080, 27660,  511,  0, PL },
-       { "Wacom DTF521",         WACOM_PKGLEN_GRAPHIRE,   6282,  4762,  511,  0, PL },
-       { "Wacom DTF720",         WACOM_PKGLEN_GRAPHIRE,   6858,  5506,  511,  0, PL },
-       { "Wacom DTF720a",        WACOM_PKGLEN_GRAPHIRE,   6858,  5506,  511,  0, PL },
-       { "Wacom Cintiq Partner", WACOM_PKGLEN_GRAPHIRE,  20480, 15360,  511,  0, PTU },
-       { "Wacom Intuos2 4x5",    WACOM_PKGLEN_INTUOS,    12700, 10600, 1023, 31, INTUOS },
-       { "Wacom Intuos2 6x8",    WACOM_PKGLEN_INTUOS,    20320, 16240, 1023, 31, INTUOS },
-       { "Wacom Intuos2 9x12",   WACOM_PKGLEN_INTUOS,    30480, 24060, 1023, 31, INTUOS },
-       { "Wacom Intuos2 12x12",  WACOM_PKGLEN_INTUOS,    30480, 31680, 1023, 31, INTUOS },
-       { "Wacom Intuos2 12x18",  WACOM_PKGLEN_INTUOS,    45720, 31680, 1023, 31, INTUOS },
-       { "Wacom Intuos3 4x5",    WACOM_PKGLEN_INTUOS,    25400, 20320, 1023, 63, INTUOS3S },
-       { "Wacom Intuos3 6x8",    WACOM_PKGLEN_INTUOS,    40640, 30480, 1023, 63, INTUOS3 },
-       { "Wacom Intuos3 9x12",   WACOM_PKGLEN_INTUOS,    60960, 45720, 1023, 63, INTUOS3 },
-       { "Wacom Intuos3 12x12",  WACOM_PKGLEN_INTUOS,    60960, 60960, 1023, 63, INTUOS3L },
-       { "Wacom Intuos3 12x19",  WACOM_PKGLEN_INTUOS,    97536, 60960, 1023, 63, INTUOS3L },
-       { "Wacom Intuos3 6x11",   WACOM_PKGLEN_INTUOS,    54204, 31750, 1023, 63, INTUOS3 },
-       { "Wacom Intuos3 4x6",    WACOM_PKGLEN_INTUOS,    31496, 19685, 1023, 63, INTUOS3S },
-       { "Wacom Intuos4 4x6",    WACOM_PKGLEN_INTUOS,    31496, 19685, 2047, 63, INTUOS4S },
-       { "Wacom Intuos4 6x9",    WACOM_PKGLEN_INTUOS,    44704, 27940, 2047, 63, INTUOS4 },
-       { "Wacom Intuos4 8x13",   WACOM_PKGLEN_INTUOS,    65024, 40640, 2047, 63, INTUOS4L },
-       { "Wacom Intuos4 12x19",  WACOM_PKGLEN_INTUOS,    97536, 60960, 2047, 63, INTUOS4L },
-       { "Wacom Cintiq 21UX",    WACOM_PKGLEN_INTUOS,    87200, 65600, 1023, 63, CINTIQ },
-       { "Wacom Cintiq 20WSX",   WACOM_PKGLEN_INTUOS,    86680, 54180, 1023, 63, WACOM_BEE },
-       { "Wacom Cintiq 12WX",    WACOM_PKGLEN_INTUOS,    53020, 33440, 1023, 63, WACOM_BEE },
-       { "Wacom DTU1931",        WACOM_PKGLEN_GRAPHIRE,  37832, 30305,  511,  0, PL },
-       { "Wacom ISDv4 90",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,  0, TABLETPC },
-       { "Wacom ISDv4 93",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,  0, TABLETPC },
-       { "Wacom ISDv4 9A",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,  0, TABLETPC },
-       { "Wacom ISDv4 9F",       WACOM_PKGLEN_PENABLED,  26202, 16325,  255,  0, TABLETPC },
-       { "Wacom ISDv4 E2",       WACOM_PKGLEN_TPC2FG,    26202, 16325,  255,  0, TABLETPC2FG },
-       { "Wacom ISDv4 E3",       WACOM_PKGLEN_TPC2FG,    26202, 16325,  255,  0, TABLETPC2FG },
-       { "Wacom Intuos2 6x8",    WACOM_PKGLEN_INTUOS,    20320, 16240, 1023, 31, INTUOS },
+static const struct wacom_features wacom_features_0x00 =
+       { "Wacom Penpartner",     WACOM_PKGLEN_PENPRTN,    5040,  3780,  255,  0, PENPARTNER };
+static const struct wacom_features wacom_features_0x10 =
+       { "Wacom Graphire",       WACOM_PKGLEN_GRAPHIRE,  10206,  7422,  511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x11 =
+       { "Wacom Graphire2 4x5",  WACOM_PKGLEN_GRAPHIRE,  10206,  7422,  511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x12 =
+       { "Wacom Graphire2 5x7",  WACOM_PKGLEN_GRAPHIRE,  13918, 10206,  511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x13 =
+       { "Wacom Graphire3",      WACOM_PKGLEN_GRAPHIRE,  10208,  7424,  511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x14 =
+       { "Wacom Graphire3 6x8",  WACOM_PKGLEN_GRAPHIRE,  16704, 12064,  511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x15 =
+       { "Wacom Graphire4 4x5",  WACOM_PKGLEN_GRAPHIRE,  10208,  7424,  511, 63, WACOM_G4 };
+static const struct wacom_features wacom_features_0x16 =
+       { "Wacom Graphire4 6x8",  WACOM_PKGLEN_GRAPHIRE,  16704, 12064,  511, 63, WACOM_G4 };
+static const struct wacom_features wacom_features_0x17 =
+       { "Wacom BambooFun 4x5",  WACOM_PKGLEN_BBFUN,     14760,  9225,  511, 63, WACOM_MO };
+static const struct wacom_features wacom_features_0x18 =
+       { "Wacom BambooFun 6x8",  WACOM_PKGLEN_BBFUN,     21648, 13530,  511, 63, WACOM_MO };
+static const struct wacom_features wacom_features_0x19 =
+       { "Wacom Bamboo1 Medium", WACOM_PKGLEN_GRAPHIRE,  16704, 12064,  511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x60 =
+       { "Wacom Volito",         WACOM_PKGLEN_GRAPHIRE,   5104,  3712,  511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x61 =
+       { "Wacom PenStation2",    WACOM_PKGLEN_GRAPHIRE,   3250,  2320,  255, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x62 =
+       { "Wacom Volito2 4x5",    WACOM_PKGLEN_GRAPHIRE,   5104,  3712,  511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x63 =
+       { "Wacom Volito2 2x3",    WACOM_PKGLEN_GRAPHIRE,   3248,  2320,  511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x64 =
+       { "Wacom PenPartner2",    WACOM_PKGLEN_GRAPHIRE,   3250,  2320,  511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x65 =
+       { "Wacom Bamboo",         WACOM_PKGLEN_BBFUN,     14760,  9225,  511, 63, WACOM_MO };
+static const struct wacom_features wacom_features_0x69 =
+       { "Wacom Bamboo1",        WACOM_PKGLEN_GRAPHIRE,   5104,  3712,  511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x20 =
+       { "Wacom Intuos 4x5",     WACOM_PKGLEN_INTUOS,    12700, 10600, 1023, 31, INTUOS };
+static const struct wacom_features wacom_features_0x21 =
+       { "Wacom Intuos 6x8",     WACOM_PKGLEN_INTUOS,    20320, 16240, 1023, 31, INTUOS };
+static const struct wacom_features wacom_features_0x22 =
+       { "Wacom Intuos 9x12",    WACOM_PKGLEN_INTUOS,    30480, 24060, 1023, 31, INTUOS };
+static const struct wacom_features wacom_features_0x23 =
+       { "Wacom Intuos 12x12",   WACOM_PKGLEN_INTUOS,    30480, 31680, 1023, 31, INTUOS };
+static const struct wacom_features wacom_features_0x24 =
+       { "Wacom Intuos 12x18",   WACOM_PKGLEN_INTUOS,    45720, 31680, 1023, 31, INTUOS };
+static const struct wacom_features wacom_features_0x30 =
+       { "Wacom PL400",          WACOM_PKGLEN_GRAPHIRE,   5408,  4056,  255,  0, PL };
+static const struct wacom_features wacom_features_0x31 =
+       { "Wacom PL500",          WACOM_PKGLEN_GRAPHIRE,   6144,  4608,  255,  0, PL };
+static const struct wacom_features wacom_features_0x32 =
+       { "Wacom PL600",          WACOM_PKGLEN_GRAPHIRE,   6126,  4604,  255,  0, PL };
+static const struct wacom_features wacom_features_0x33 =
+       { "Wacom PL600SX",        WACOM_PKGLEN_GRAPHIRE,   6260,  5016,  255,  0, PL };
+static const struct wacom_features wacom_features_0x34 =
+       { "Wacom PL550",          WACOM_PKGLEN_GRAPHIRE,   6144,  4608,  511,  0, PL };
+static const struct wacom_features wacom_features_0x35 =
+       { "Wacom PL800",          WACOM_PKGLEN_GRAPHIRE,   7220,  5780,  511,  0, PL };
+static const struct wacom_features wacom_features_0x37 =
+       { "Wacom PL700",          WACOM_PKGLEN_GRAPHIRE,   6758,  5406,  511,  0, PL };
+static const struct wacom_features wacom_features_0x38 =
+       { "Wacom PL510",          WACOM_PKGLEN_GRAPHIRE,   6282,  4762,  511,  0, PL };
+static const struct wacom_features wacom_features_0x39 =
+       { "Wacom DTU710",         WACOM_PKGLEN_GRAPHIRE,  34080, 27660,  511,  0, PL };
+static const struct wacom_features wacom_features_0xC4 =
+       { "Wacom DTF521",         WACOM_PKGLEN_GRAPHIRE,   6282,  4762,  511,  0, PL };
+static const struct wacom_features wacom_features_0xC0 =
+       { "Wacom DTF720",         WACOM_PKGLEN_GRAPHIRE,   6858,  5506,  511,  0, PL };
+static const struct wacom_features wacom_features_0xC2 =
+       { "Wacom DTF720a",        WACOM_PKGLEN_GRAPHIRE,   6858,  5506,  511,  0, PL };
+static const struct wacom_features wacom_features_0x03 =
+       { "Wacom Cintiq Partner", WACOM_PKGLEN_GRAPHIRE,  20480, 15360,  511,  0, PTU };
+static const struct wacom_features wacom_features_0x41 =
+       { "Wacom Intuos2 4x5",    WACOM_PKGLEN_INTUOS,    12700, 10600, 1023, 31, INTUOS };
+static const struct wacom_features wacom_features_0x42 =
+       { "Wacom Intuos2 6x8",    WACOM_PKGLEN_INTUOS,    20320, 16240, 1023, 31, INTUOS };
+static const struct wacom_features wacom_features_0x43 =
+       { "Wacom Intuos2 9x12",   WACOM_PKGLEN_INTUOS,    30480, 24060, 1023, 31, INTUOS };
+static const struct wacom_features wacom_features_0x44 =
+       { "Wacom Intuos2 12x12",  WACOM_PKGLEN_INTUOS,    30480, 31680, 1023, 31, INTUOS };
+static const struct wacom_features wacom_features_0x45 =
+       { "Wacom Intuos2 12x18",  WACOM_PKGLEN_INTUOS,    45720, 31680, 1023, 31, INTUOS };
+static const struct wacom_features wacom_features_0xB0 =
+       { "Wacom Intuos3 4x5",    WACOM_PKGLEN_INTUOS,    25400, 20320, 1023, 63, INTUOS3S };
+static const struct wacom_features wacom_features_0xB1 =
+       { "Wacom Intuos3 6x8",    WACOM_PKGLEN_INTUOS,    40640, 30480, 1023, 63, INTUOS3 };
+static const struct wacom_features wacom_features_0xB2 =
+       { "Wacom Intuos3 9x12",   WACOM_PKGLEN_INTUOS,    60960, 45720, 1023, 63, INTUOS3 };
+static const struct wacom_features wacom_features_0xB3 =
+       { "Wacom Intuos3 12x12",  WACOM_PKGLEN_INTUOS,    60960, 60960, 1023, 63, INTUOS3L };
+static const struct wacom_features wacom_features_0xB4 =
+       { "Wacom Intuos3 12x19",  WACOM_PKGLEN_INTUOS,    97536, 60960, 1023, 63, INTUOS3L };
+static const struct wacom_features wacom_features_0xB5 =
+       { "Wacom Intuos3 6x11",   WACOM_PKGLEN_INTUOS,    54204, 31750, 1023, 63, INTUOS3 };
+static const struct wacom_features wacom_features_0xB7 =
+       { "Wacom Intuos3 4x6",    WACOM_PKGLEN_INTUOS,    31496, 19685, 1023, 63, INTUOS3S };
+static const struct wacom_features wacom_features_0xB8 =
+       { "Wacom Intuos4 4x6",    WACOM_PKGLEN_INTUOS,    31496, 19685, 2047, 63, INTUOS4S };
+static const struct wacom_features wacom_features_0xB9 =
+       { "Wacom Intuos4 6x9",    WACOM_PKGLEN_INTUOS,    44704, 27940, 2047, 63, INTUOS4 };
+static const struct wacom_features wacom_features_0xBA =
+       { "Wacom Intuos4 8x13",   WACOM_PKGLEN_INTUOS,    65024, 40640, 2047, 63, INTUOS4L };
+static const struct wacom_features wacom_features_0xBB =
+       { "Wacom Intuos4 12x19",  WACOM_PKGLEN_INTUOS,    97536, 60960, 2047, 63, INTUOS4L };
+static const struct wacom_features wacom_features_0x3F =
+       { "Wacom Cintiq 21UX",    WACOM_PKGLEN_INTUOS,    87200, 65600, 1023, 63, CINTIQ };
+static const struct wacom_features wacom_features_0xC5 =
+       { "Wacom Cintiq 20WSX",   WACOM_PKGLEN_INTUOS,    86680, 54180, 1023, 63, WACOM_BEE };
+static const struct wacom_features wacom_features_0xC6 =
+       { "Wacom Cintiq 12WX",    WACOM_PKGLEN_INTUOS,    53020, 33440, 1023, 63, WACOM_BEE };
+static const struct wacom_features wacom_features_0xC7 =
+       { "Wacom DTU1931",        WACOM_PKGLEN_GRAPHIRE,  37832, 30305,  511,  0, PL };
+static const struct wacom_features wacom_features_0x90 =
+       { "Wacom ISDv4 90",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,  0, TABLETPC };
+static const struct wacom_features wacom_features_0x93 =
+       { "Wacom ISDv4 93",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,  0, TABLETPC };
+static const struct wacom_features wacom_features_0x9A =
+       { "Wacom ISDv4 9A",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,  0, TABLETPC };
+static const struct wacom_features wacom_features_0x9F =
+       { "Wacom ISDv4 9F",       WACOM_PKGLEN_PENABLED,  26202, 16325,  255,  0, TABLETPC };
+static const struct wacom_features wacom_features_0xE2 =
+       { "Wacom ISDv4 E2",       WACOM_PKGLEN_TPC2FG,    26202, 16325,  255,  0, TABLETPC2FG };
+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 };
+
+#define USB_DEVICE_WACOM(prod)                                 \
+       USB_DEVICE(USB_VENDOR_ID_WACOM, prod),                  \
+       .driver_info = (kernel_ulong_t)&wacom_features_##prod
+
+const struct usb_device_id wacom_ids[] = {
+       { USB_DEVICE_WACOM(0x00) },
+       { USB_DEVICE_WACOM(0x10) },
+       { USB_DEVICE_WACOM(0x11) },
+       { USB_DEVICE_WACOM(0x12) },
+       { USB_DEVICE_WACOM(0x13) },
+       { USB_DEVICE_WACOM(0x14) },
+       { USB_DEVICE_WACOM(0x15) },
+       { USB_DEVICE_WACOM(0x16) },
+       { USB_DEVICE_WACOM(0x17) },
+       { USB_DEVICE_WACOM(0x18) },
+       { USB_DEVICE_WACOM(0x19) },
+       { USB_DEVICE_WACOM(0x60) },
+       { USB_DEVICE_WACOM(0x61) },
+       { USB_DEVICE_WACOM(0x62) },
+       { USB_DEVICE_WACOM(0x63) },
+       { USB_DEVICE_WACOM(0x64) },
+       { USB_DEVICE_WACOM(0x65) },
+       { USB_DEVICE_WACOM(0x69) },
+       { USB_DEVICE_WACOM(0x20) },
+       { USB_DEVICE_WACOM(0x21) },
+       { USB_DEVICE_WACOM(0x22) },
+       { USB_DEVICE_WACOM(0x23) },
+       { USB_DEVICE_WACOM(0x24) },
+       { USB_DEVICE_WACOM(0x30) },
+       { USB_DEVICE_WACOM(0x31) },
+       { USB_DEVICE_WACOM(0x32) },
+       { USB_DEVICE_WACOM(0x33) },
+       { USB_DEVICE_WACOM(0x34) },
+       { USB_DEVICE_WACOM(0x35) },
+       { USB_DEVICE_WACOM(0x37) },
+       { USB_DEVICE_WACOM(0x38) },
+       { USB_DEVICE_WACOM(0x39) },
+       { USB_DEVICE_WACOM(0xC4) },
+       { USB_DEVICE_WACOM(0xC0) },
+       { USB_DEVICE_WACOM(0xC2) },
+       { USB_DEVICE_WACOM(0x03) },
+       { USB_DEVICE_WACOM(0x41) },
+       { USB_DEVICE_WACOM(0x42) },
+       { USB_DEVICE_WACOM(0x43) },
+       { USB_DEVICE_WACOM(0x44) },
+       { USB_DEVICE_WACOM(0x45) },
+       { USB_DEVICE_WACOM(0xB0) },
+       { USB_DEVICE_WACOM(0xB1) },
+       { USB_DEVICE_WACOM(0xB2) },
+       { USB_DEVICE_WACOM(0xB3) },
+       { USB_DEVICE_WACOM(0xB4) },
+       { USB_DEVICE_WACOM(0xB5) },
+       { USB_DEVICE_WACOM(0xB7) },
+       { USB_DEVICE_WACOM(0xB8) },
+       { USB_DEVICE_WACOM(0xB9) },
+       { USB_DEVICE_WACOM(0xBA) },
+       { USB_DEVICE_WACOM(0xBB) },
+       { USB_DEVICE_WACOM(0x3F) },
+       { USB_DEVICE_WACOM(0xC5) },
+       { USB_DEVICE_WACOM(0xC6) },
+       { USB_DEVICE_WACOM(0xC7) },
+       { USB_DEVICE_WACOM(0x90) },
+       { USB_DEVICE_WACOM(0x93) },
+       { USB_DEVICE_WACOM(0x9A) },
+       { USB_DEVICE_WACOM(0x9F) },
+       { USB_DEVICE_WACOM(0xE2) },
+       { USB_DEVICE_WACOM(0xE3) },
+       { USB_DEVICE_WACOM(0x47) },
        { }
 };
-
-static struct usb_device_id wacom_ids[] = {
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x00) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x10) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x11) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x12) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x13) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x14) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x15) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x16) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x17) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x18) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x19) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x60) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x61) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x62) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x63) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x64) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x65) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x69) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x20) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x21) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x22) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x23) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x24) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x30) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x31) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x32) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x33) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x34) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x35) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x37) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x38) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x39) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC4) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC0) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC2) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x03) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x41) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x42) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x43) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x44) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x45) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB0) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB1) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB2) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB3) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB4) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB5) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB7) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB8) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB9) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xBA) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xBB) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC5) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC6) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC7) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x90) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x93) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x9A) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x9F) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xE2) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xE3) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) },
-       { }
-};
-
-const struct usb_device_id *get_device_table(void)
-{
-        const struct usb_device_id *id_table = wacom_ids;
-
-        return id_table;
-}
-
-struct wacom_features * get_wacom_feature(const struct usb_device_id *id)
-{
-        int index = id - wacom_ids;
-        struct wacom_features *wf = &wacom_features[index];
-
-        return wf;
-}
-
 MODULE_DEVICE_TABLE(usb, wacom_ids);
index ee01e19027850fb70b5a61fae8d77843a8d7a981..8590b1e8ec3774294decc187a91e995bb0477bbc 100644 (file)
 /* packet length for individual models */
 #define WACOM_PKGLEN_PENPRTN    7
 #define WACOM_PKGLEN_GRAPHIRE   8
-#define WACOM_PKGLEN_BBFUN      9
-#define WACOM_PKGLEN_INTUOS    10
+#define WACOM_PKGLEN_BBFUN      9
+#define WACOM_PKGLEN_INTUOS    10
 #define WACOM_PKGLEN_PENABLED   8
 #define WACOM_PKGLEN_TPC1FG     5
-#define WACOM_PKGLEN_TPC2FG    14
+#define WACOM_PKGLEN_TPC2FG    14
 
 /* device IDs */
 #define STYLUS_DEVICE_ID       0x02
@@ -58,7 +58,7 @@ enum {
 };
 
 struct wacom_features {
-       char *name;
+       const char *name;
        int pktlen;
        int x_max;
        int y_max;
@@ -73,11 +73,12 @@ struct wacom_features {
 };
 
 struct wacom_wac {
+       char name[64];
        unsigned char *data;
-        int tool[2];
-        int id[2];
-        __u32 serial[2];
-       struct wacom_features *features;
+       int tool[2];
+       int id[2];
+       __u32 serial[2];
+       struct wacom_features features;
 };
 
 #endif
index dfafc76da4fbfbd2f6fb3d86f19e5ac6f6154be5..6457e060ae4915b421a61834880986952e094b6e 100644 (file)
@@ -90,7 +90,6 @@ config TOUCHSCREEN_CORGI
        tristate "SharpSL (Corgi and Spitz series) touchscreen driver (DEPRECATED)"
        depends on PXA_SHARPSL
        select CORGI_SSP_DEPRECATED
-       default y
        help
          Say Y here to enable the driver for the touchscreen on the
          Sharp SL-C7xx and SL-Cxx00 series of PDAs.
@@ -537,6 +536,11 @@ config TOUCHSCREEN_USB_ETT_TC5UH
        bool "ET&T TC5UH touchscreen controler support" if EMBEDDED
        depends on TOUCHSCREEN_USB_COMPOSITE
 
+config TOUCHSCREEN_USB_NEXIO
+       default y
+       bool "NEXIO/iNexio device support" if EMBEDDED
+       depends on TOUCHSCREEN_USB_COMPOSITE
+
 config TOUCHSCREEN_TOUCHIT213
        tristate "Sahara TouchIT-213 touchscreen"
        select SERIO
index 52d2ca147d8f004a3f24c4d5df4a80365300bd4c..8b05d8e975437501d73378d401e90a857db72d40 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/gpio.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
+#include <linux/regulator/consumer.h>
 #include <asm/irq.h>
 
 /*
@@ -85,6 +86,7 @@ struct ads7846 {
        char                    name[32];
 
        struct spi_device       *spi;
+       struct regulator        *reg;
 
 #if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
        struct attribute_group  *attr_group;
@@ -788,6 +790,8 @@ static void ads7846_disable(struct ads7846 *ts)
                }
        }
 
+       regulator_disable(ts->reg);
+
        /* we know the chip's in lowpower mode since we always
         * leave it that way after every request
         */
@@ -799,6 +803,8 @@ static void ads7846_enable(struct ads7846 *ts)
        if (!ts->disabled)
                return;
 
+       regulator_enable(ts->reg);
+
        ts->disabled = 0;
        ts->irq_disabled = 0;
        enable_irq(ts->spi->irq);
@@ -1139,6 +1145,19 @@ static int __devinit ads7846_probe(struct spi_device *spi)
 
        ts->last_msg = m;
 
+       ts->reg = regulator_get(&spi->dev, "vcc");
+       if (IS_ERR(ts->reg)) {
+               dev_err(&spi->dev, "unable to get regulator: %ld\n",
+                       PTR_ERR(ts->reg));
+               goto err_free_gpio;
+       }
+
+       err = regulator_enable(ts->reg);
+       if (err) {
+               dev_err(&spi->dev, "unable to enable regulator: %d\n", err);
+               goto err_put_regulator;
+       }
+
        if (request_irq(spi->irq, ads7846_irq, IRQF_TRIGGER_FALLING,
                        spi->dev.driver->name, ts)) {
                dev_info(&spi->dev,
@@ -1148,7 +1167,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
                                  spi->dev.driver->name, ts);
                if (err) {
                        dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
-                       goto err_free_gpio;
+                       goto err_disable_regulator;
                }
        }
 
@@ -1180,6 +1199,10 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        ads784x_hwmon_unregister(spi, ts);
  err_free_irq:
        free_irq(spi->irq, ts);
+ err_disable_regulator:
+       regulator_disable(ts->reg);
+ err_put_regulator:
+       regulator_put(ts->reg);
  err_free_gpio:
        if (ts->gpio_pendown != -1)
                gpio_free(ts->gpio_pendown);
@@ -1208,6 +1231,9 @@ static int __devexit ads7846_remove(struct spi_device *spi)
        /* suspend left the IRQ disabled */
        enable_irq(ts->spi->irq);
 
+       regulator_disable(ts->reg);
+       regulator_put(ts->reg);
+
        if (ts->gpio_pendown != -1)
                gpio_free(ts->gpio_pendown);
 
index 8f38c5e55ce6136782086534bdbf08e993f67702..486d31ba9c0952b28f95e73baa75a78b53316255 100644 (file)
@@ -72,45 +72,49 @@ static void elo_process_data_10(struct elo *elo, unsigned char data)
        struct input_dev *dev = elo->dev;
 
        elo->data[elo->idx] = data;
-       switch (elo->idx++) {
-               case 0:
-                       elo->csum = 0xaa;
-                       if (data != ELO10_LEAD_BYTE) {
-                               pr_debug("elo: unsynchronized data: 0x%02x\n", data);
-                               elo->idx = 0;
-                       }
-                       break;
 
-               case 9:
+       switch (elo->idx++) {
+       case 0:
+               elo->csum = 0xaa;
+               if (data != ELO10_LEAD_BYTE) {
+                       dev_dbg(&elo->serio->dev,
+                               "unsynchronized data: 0x%02x\n", data);
                        elo->idx = 0;
-                       if (data != elo->csum) {
-                               pr_debug("elo: bad checksum: 0x%02x, expected 0x%02x\n",
-                                        data, elo->csum);
-                               break;
-                       }
-                       if (elo->data[1] != elo->expected_packet) {
-                               if (elo->data[1] != ELO10_TOUCH_PACKET)
-                                       pr_debug("elo: unexpected packet: 0x%02x\n",
-                                                elo->data[1]);
-                               break;
-                       }
-                       if (likely(elo->data[1] == ELO10_TOUCH_PACKET)) {
-                               input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]);
-                               input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]);
-                               if (elo->data[2] & ELO10_PRESSURE)
-                                       input_report_abs(dev, ABS_PRESSURE,
-                                                       (elo->data[8] << 8) | elo->data[7]);
-                               input_report_key(dev, BTN_TOUCH, elo->data[2] & ELO10_TOUCH);
-                               input_sync(dev);
-                       } else if (elo->data[1] == ELO10_ACK_PACKET) {
-                               if (elo->data[2] == '0')
-                                       elo->expected_packet = ELO10_TOUCH_PACKET;
-                               complete(&elo->cmd_done);
-                       } else {
-                               memcpy(elo->response, &elo->data[1], ELO10_PACKET_LEN);
-                               elo->expected_packet = ELO10_ACK_PACKET;
-                       }
+               }
+               break;
+
+       case 9:
+               elo->idx = 0;
+               if (data != elo->csum) {
+                       dev_dbg(&elo->serio->dev,
+                               "bad checksum: 0x%02x, expected 0x%02x\n",
+                                data, elo->csum);
+                       break;
+               }
+               if (elo->data[1] != elo->expected_packet) {
+                       if (elo->data[1] != ELO10_TOUCH_PACKET)
+                               dev_dbg(&elo->serio->dev,
+                                       "unexpected packet: 0x%02x\n",
+                                        elo->data[1]);
                        break;
+               }
+               if (likely(elo->data[1] == ELO10_TOUCH_PACKET)) {
+                       input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]);
+                       input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]);
+                       if (elo->data[2] & ELO10_PRESSURE)
+                               input_report_abs(dev, ABS_PRESSURE,
+                                               (elo->data[8] << 8) | elo->data[7]);
+                       input_report_key(dev, BTN_TOUCH, elo->data[2] & ELO10_TOUCH);
+                       input_sync(dev);
+               } else if (elo->data[1] == ELO10_ACK_PACKET) {
+                       if (elo->data[2] == '0')
+                               elo->expected_packet = ELO10_TOUCH_PACKET;
+                       complete(&elo->cmd_done);
+               } else {
+                       memcpy(elo->response, &elo->data[1], ELO10_PACKET_LEN);
+                       elo->expected_packet = ELO10_ACK_PACKET;
+               }
+               break;
        }
        elo->csum += data;
 }
@@ -123,42 +127,53 @@ static void elo_process_data_6(struct elo *elo, unsigned char data)
 
        switch (elo->idx++) {
 
-               case 0: if ((data & 0xc0) != 0xc0) elo->idx = 0; break;
-               case 1: if ((data & 0xc0) != 0x80) elo->idx = 0; break;
-               case 2: if ((data & 0xc0) != 0x40) elo->idx = 0; break;
-
-               case 3:
-                       if (data & 0xc0) {
-                               elo->idx = 0;
-                               break;
-                       }
+       case 0:
+               if ((data & 0xc0) != 0xc0)
+                       elo->idx = 0;
+               break;
 
-                       input_report_abs(dev, ABS_X, ((elo->data[0] & 0x3f) << 6) | (elo->data[1] & 0x3f));
-                       input_report_abs(dev, ABS_Y, ((elo->data[2] & 0x3f) << 6) | (elo->data[3] & 0x3f));
+       case 1:
+               if ((data & 0xc0) != 0x80)
+                       elo->idx = 0;
+               break;
 
-                       if (elo->id == 2) {
-                               input_report_key(dev, BTN_TOUCH, 1);
-                               input_sync(dev);
-                               elo->idx = 0;
-                       }
+       case 2:
+               if ((data & 0xc0) != 0x40)
+                       elo->idx = 0;
+               break;
 
+       case 3:
+               if (data & 0xc0) {
+                       elo->idx = 0;
                        break;
+               }
 
-               case 4:
-                       if (data) {
-                               input_sync(dev);
-                               elo->idx = 0;
-                       }
-                       break;
+               input_report_abs(dev, ABS_X, ((elo->data[0] & 0x3f) << 6) | (elo->data[1] & 0x3f));
+               input_report_abs(dev, ABS_Y, ((elo->data[2] & 0x3f) << 6) | (elo->data[3] & 0x3f));
 
-               case 5:
-                       if ((data & 0xf0) == 0) {
-                               input_report_abs(dev, ABS_PRESSURE, elo->data[5]);
-                               input_report_key(dev, BTN_TOUCH, !!elo->data[5]);
-                       }
+               if (elo->id == 2) {
+                       input_report_key(dev, BTN_TOUCH, 1);
                        input_sync(dev);
                        elo->idx = 0;
-                       break;
+               }
+
+               break;
+
+       case 4:
+               if (data) {
+                       input_sync(dev);
+                       elo->idx = 0;
+               }
+               break;
+
+       case 5:
+               if ((data & 0xf0) == 0) {
+                       input_report_abs(dev, ABS_PRESSURE, elo->data[5]);
+                       input_report_key(dev, BTN_TOUCH, !!elo->data[5]);
+               }
+               input_sync(dev);
+               elo->idx = 0;
+               break;
        }
 }
 
@@ -170,17 +185,17 @@ static void elo_process_data_3(struct elo *elo, unsigned char data)
 
        switch (elo->idx++) {
 
-               case 0:
-                       if ((data & 0x7f) != 0x01)
-                               elo->idx = 0;
-                       break;
-               case 2:
-                       input_report_key(dev, BTN_TOUCH, !(elo->data[1] & 0x80));
-                       input_report_abs(dev, ABS_X, elo->data[1]);
-                       input_report_abs(dev, ABS_Y, elo->data[2]);
-                       input_sync(dev);
+       case 0:
+               if ((data & 0x7f) != 0x01)
                        elo->idx = 0;
-                       break;
+               break;
+       case 2:
+               input_report_key(dev, BTN_TOUCH, !(elo->data[1] & 0x80));
+               input_report_abs(dev, ABS_X, elo->data[1]);
+               input_report_abs(dev, ABS_Y, elo->data[2]);
+               input_sync(dev);
+               elo->idx = 0;
+               break;
        }
 }
 
@@ -189,19 +204,19 @@ static irqreturn_t elo_interrupt(struct serio *serio,
 {
        struct elo *elo = serio_get_drvdata(serio);
 
-       switch(elo->id) {
-               case 0:
-                       elo_process_data_10(elo, data);
-                       break;
-
-               case 1:
-               case 2:
-                       elo_process_data_6(elo, data);
-                       break;
-
-               case 3:
-                       elo_process_data_3(elo, data);
-                       break;
+       switch (elo->id) {
+       case 0:
+               elo_process_data_10(elo, data);
+               break;
+
+       case 1:
+       case 2:
+               elo_process_data_6(elo, data);
+               break;
+
+       case 3:
+               elo_process_data_3(elo, data);
+               break;
        }
 
        return IRQ_HANDLED;
@@ -261,10 +276,10 @@ static int elo_setup_10(struct elo *elo)
        if (packet[3] & ELO10_PRESSURE)
                input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
 
-       printk(KERN_INFO "elo: %sTouch touchscreen, fw: %02x.%02x, "
-               "features: 0x%02x, controller: 0x%02x\n",
-               elo_types[(packet[1] -'0') & 0x03],
-               packet[5], packet[4], packet[3], packet[7]);
+       dev_info(&elo->serio->dev,
+                "%sTouch touchscreen, fw: %02x.%02x, features: 0x%02x, controller: 0x%02x\n",
+                elo_types[(packet[1] -'0') & 0x03],
+                packet[5], packet[4], packet[3], packet[7]);
 
        return 0;
 }
@@ -330,24 +345,24 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv)
 
        switch (elo->id) {
 
-               case 0: /* 10-byte protocol */
-                       if (elo_setup_10(elo))
-                               goto fail3;
+       case 0: /* 10-byte protocol */
+               if (elo_setup_10(elo))
+                       goto fail3;
 
-                       break;
+               break;
 
-               case 1: /* 6-byte protocol */
-                       input_set_abs_params(input_dev, ABS_PRESSURE, 0, 15, 0, 0);
+       case 1: /* 6-byte protocol */
+               input_set_abs_params(input_dev, ABS_PRESSURE, 0, 15, 0, 0);
 
-               case 2: /* 4-byte protocol */
-                       input_set_abs_params(input_dev, ABS_X, 96, 4000, 0, 0);
-                       input_set_abs_params(input_dev, ABS_Y, 96, 4000, 0, 0);
-                       break;
+       case 2: /* 4-byte protocol */
+               input_set_abs_params(input_dev, ABS_X, 96, 4000, 0, 0);
+               input_set_abs_params(input_dev, ABS_Y, 96, 4000, 0, 0);
+               break;
 
-               case 3: /* 3-byte protocol */
-                       input_set_abs_params(input_dev, ABS_X, 0, 255, 0, 0);
-                       input_set_abs_params(input_dev, ABS_Y, 0, 255, 0, 0);
-                       break;
+       case 3: /* 3-byte protocol */
+               input_set_abs_params(input_dev, ABS_X, 0, 255, 0, 0);
+               input_set_abs_params(input_dev, ABS_Y, 0, 255, 0, 0);
+               break;
        }
 
        err = input_register_device(elo->dev);
index 6cdcf2a6e0365b2dd78a78bb25ae03ebcb9ee757..b6b8b1c7eceaf99b6eec1d613f3511c4a4a65550 100644 (file)
@@ -153,6 +153,9 @@ static int wm97xx_acc_pen_down(struct wm97xx *wm)
                if (pressure)
                        p = MODR;
 
+               dev_dbg(wm->dev, "Raw coordinates: x=%x, y=%x, p=%x\n",
+                       x, y, p);
+
                /* are samples valid */
                if ((x & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_X ||
                    (y & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_Y ||
index 6386b441ef855f337d6ff71a4d45ebce443625ee..3755a47d053caea796fd4650c18889e0f7ea4fa4 100644 (file)
@@ -128,27 +128,29 @@ static void touch_timer_fire(unsigned long data)
 
        down = get_down(data0, data1);
 
-       if (ts.count == (1 << ts.shift)) {
-               ts.xp >>= ts.shift;
-               ts.yp >>= ts.shift;
+       if (down) {
+               if (ts.count == (1 << ts.shift)) {
+                       ts.xp >>= ts.shift;
+                       ts.yp >>= ts.shift;
 
-               dev_dbg(ts.dev, "%s: X=%lu, Y=%lu, count=%d\n",
-                       __func__, ts.xp, ts.yp, ts.count);
+                       dev_dbg(ts.dev, "%s: X=%lu, Y=%lu, count=%d\n",
+                               __func__, ts.xp, ts.yp, ts.count);
 
-               input_report_abs(ts.input, ABS_X, ts.xp);
-               input_report_abs(ts.input, ABS_Y, ts.yp);
+                       input_report_abs(ts.input, ABS_X, ts.xp);
+                       input_report_abs(ts.input, ABS_Y, ts.yp);
 
-               input_report_key(ts.input, BTN_TOUCH, 1);
-               input_sync(ts.input);
+                       input_report_key(ts.input, BTN_TOUCH, 1);
+                       input_sync(ts.input);
 
-               ts.xp = 0;
-               ts.yp = 0;
-               ts.count = 0;
-       }
+                       ts.xp = 0;
+                       ts.yp = 0;
+                       ts.count = 0;
+               }
 
-       if (down) {
                s3c_adc_start(ts.client, 0, 1 << ts.shift);
        } else {
+               ts.xp = 0;
+               ts.yp = 0;
                ts.count = 0;
 
                input_report_key(ts.input, BTN_TOUCH, 0);
@@ -401,6 +403,7 @@ static int s3c2410ts_resume(struct device *dev)
        struct s3c2410_ts_mach_info *info = pdev->dev.platform_data;
 
        clk_enable(ts.clock);
+       enable_irq(ts.irq_tc);
 
        /* Initialise registers */
        if ((info->delay & 0xffff) > 0)
index 7ef0d1420d3c917f48d4dd41013d4d4a6f7665f5..be23780e8a3e3b81be9df7b7cd0f8aab86d87e61 100644 (file)
@@ -358,7 +358,7 @@ static int __devexit tsc2007_remove(struct i2c_client *client)
        return 0;
 }
 
-static struct i2c_device_id tsc2007_idtable[] = {
+static const struct i2c_device_id tsc2007_idtable[] = {
        { "tsc2007", 0 },
        { }
 };
index 5256123a52285c35ed352d980ec7ad4641f941ee..99330bbdbac761c7f4d940f6b475861eec0bcf91 100644 (file)
@@ -15,6 +15,7 @@
  *  - GoTop Super_Q2/GogoPen/PenPower tablets
  *  - JASTEC USB touch controller/DigiTech DTR-02U
  *  - Zytronic capacitive touchscreen
+ *  - NEXIO/iNexio
  *
  * Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch>
  * Copyright (C) by Todd E. Johnson (mtouchusb.c)
@@ -95,6 +96,7 @@ struct usbtouch_device_info {
 
        int  (*read_data)   (struct usbtouch_usb *usbtouch, unsigned char *pkt);
        int  (*init)        (struct usbtouch_usb *usbtouch);
+       void (*exit)        (struct usbtouch_usb *usbtouch);
 };
 
 /* a usbtouch device */
@@ -104,11 +106,12 @@ struct usbtouch_usb {
        unsigned char *buffer;
        int buf_len;
        struct urb *irq;
-       struct usb_device *udev;
+       struct usb_interface *interface;
        struct input_dev *input;
        struct usbtouch_device_info *type;
        char name[128];
        char phys[64];
+       void *priv;
 
        int x, y;
        int touch, press;
@@ -133,6 +136,7 @@ enum {
        DEVTYPE_E2I,
        DEVTYPE_ZYTRONIC,
        DEVTYPE_TC5UH,
+       DEVTYPE_NEXIO,
 };
 
 #define USB_DEVICE_HID_CLASS(vend, prod) \
@@ -144,7 +148,7 @@ enum {
        .bInterfaceClass = USB_INTERFACE_CLASS_HID, \
        .bInterfaceProtocol = USB_INTERFACE_PROTOCOL_MOUSE
 
-static struct usb_device_id usbtouch_devices[] = {
+static const struct usb_device_id usbtouch_devices[] = {
 #ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
        /* ignore the HID capable devices, handled by usbhid */
        {USB_DEVICE_HID_CLASS(0x0eef, 0x0001), .driver_info = DEVTYPE_IGNORE},
@@ -222,6 +226,14 @@ static struct usb_device_id usbtouch_devices[] = {
        {USB_DEVICE(0x0664, 0x0309), .driver_info = DEVTYPE_TC5UH},
 #endif
 
+#ifdef CONFIG_TOUCHSCREEN_USB_NEXIO
+       /* data interface only */
+       {USB_DEVICE_AND_INTERFACE_INFO(0x10f0, 0x2002, 0x0a, 0x00, 0x00),
+               .driver_info = DEVTYPE_NEXIO},
+       {USB_DEVICE_AND_INTERFACE_INFO(0x1870, 0x0001, 0x0a, 0x00, 0x00),
+               .driver_info = DEVTYPE_NEXIO},
+#endif
+
        {}
 };
 
@@ -234,8 +246,9 @@ static struct usb_device_id usbtouch_devices[] = {
 static int e2i_init(struct usbtouch_usb *usbtouch)
 {
        int ret;
+       struct usb_device *udev = interface_to_usbdev(usbtouch->interface);
 
-       ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
+       ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
                              0x01, 0x02, 0x0000, 0x0081,
                              NULL, 0, USB_CTRL_SET_TIMEOUT);
 
@@ -344,8 +357,9 @@ static int mtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
 static int mtouch_init(struct usbtouch_usb *usbtouch)
 {
        int ret, i;
+       struct usb_device *udev = interface_to_usbdev(usbtouch->interface);
 
-       ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
+       ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
                              MTOUCHUSB_RESET,
                              USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                              1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
@@ -356,7 +370,7 @@ static int mtouch_init(struct usbtouch_usb *usbtouch)
        msleep(150);
 
        for (i = 0; i < 3; i++) {
-               ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
+               ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
                                      MTOUCHUSB_ASYNC_REPORT,
                                      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                                      1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT);
@@ -489,7 +503,7 @@ static int gunze_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
 
 static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
 {
-       struct usb_device *dev = usbtouch->udev;
+       struct usb_device *dev = interface_to_usbdev(usbtouch->interface);
        int ret = -ENOMEM;
        unsigned char *buf;
 
@@ -689,6 +703,229 @@ static int zytronic_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
 }
 #endif
 
+/*****************************************************************************
+ * NEXIO Part
+ */
+#ifdef CONFIG_TOUCHSCREEN_USB_NEXIO
+
+#define NEXIO_TIMEOUT  5000
+#define NEXIO_BUFSIZE  1024
+#define NEXIO_THRESHOLD        50
+
+struct nexio_priv {
+       struct urb *ack;
+       unsigned char *ack_buf;
+};
+
+struct nexio_touch_packet {
+       u8      flags;          /* 0xe1 = touch, 0xe1 = release */
+       __be16  data_len;       /* total bytes of touch data */
+       __be16  x_len;          /* bytes for X axis */
+       __be16  y_len;          /* bytes for Y axis */
+       u8      data[];
+} __attribute__ ((packed));
+
+static unsigned char nexio_ack_pkt[2] = { 0xaa, 0x02 };
+static unsigned char nexio_init_pkt[4] = { 0x82, 0x04, 0x0a, 0x0f };
+
+static void nexio_ack_complete(struct urb *urb)
+{
+}
+
+static int nexio_init(struct usbtouch_usb *usbtouch)
+{
+       struct usb_device *dev = interface_to_usbdev(usbtouch->interface);
+       struct usb_host_interface *interface = usbtouch->interface->cur_altsetting;
+       struct nexio_priv *priv;
+       int ret = -ENOMEM;
+       int actual_len, i;
+       unsigned char *buf;
+       char *firmware_ver = NULL, *device_name = NULL;
+       int input_ep = 0, output_ep = 0;
+
+       /* find first input and output endpoint */
+       for (i = 0; i < interface->desc.bNumEndpoints; i++) {
+               if (!input_ep &&
+                   usb_endpoint_dir_in(&interface->endpoint[i].desc))
+                       input_ep = interface->endpoint[i].desc.bEndpointAddress;
+               if (!output_ep &&
+                   usb_endpoint_dir_out(&interface->endpoint[i].desc))
+                       output_ep = interface->endpoint[i].desc.bEndpointAddress;
+       }
+       if (!input_ep || !output_ep)
+               return -ENXIO;
+
+       buf = kmalloc(NEXIO_BUFSIZE, GFP_KERNEL);
+       if (!buf)
+               goto out_buf;
+
+       /* two empty reads */
+       for (i = 0; i < 2; i++) {
+               ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, input_ep),
+                                  buf, NEXIO_BUFSIZE, &actual_len,
+                                  NEXIO_TIMEOUT);
+               if (ret < 0)
+                       goto out_buf;
+       }
+
+       /* send init command */
+       memcpy(buf, nexio_init_pkt, sizeof(nexio_init_pkt));
+       ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, output_ep),
+                          buf, sizeof(nexio_init_pkt), &actual_len,
+                          NEXIO_TIMEOUT);
+       if (ret < 0)
+               goto out_buf;
+
+       /* read replies */
+       for (i = 0; i < 3; i++) {
+               memset(buf, 0, NEXIO_BUFSIZE);
+               ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, input_ep),
+                                  buf, NEXIO_BUFSIZE, &actual_len,
+                                  NEXIO_TIMEOUT);
+               if (ret < 0 || actual_len < 1 || buf[1] != actual_len)
+                       continue;
+               switch (buf[0]) {
+               case 0x83:      /* firmware version */
+                       if (!firmware_ver)
+                               firmware_ver = kstrdup(&buf[2], GFP_KERNEL);
+                       break;
+               case 0x84:      /* device name */
+                       if (!device_name)
+                               device_name = kstrdup(&buf[2], GFP_KERNEL);
+                       break;
+               }
+       }
+
+       printk(KERN_INFO "Nexio device: %s, firmware version: %s\n",
+              device_name, firmware_ver);
+
+       kfree(firmware_ver);
+       kfree(device_name);
+
+       /* prepare ACK URB */
+       ret = -ENOMEM;
+
+       usbtouch->priv = kmalloc(sizeof(struct nexio_priv), GFP_KERNEL);
+       if (!usbtouch->priv)
+               goto out_buf;
+
+       priv = usbtouch->priv;
+
+       priv->ack_buf = kmalloc(sizeof(nexio_ack_pkt), GFP_KERNEL);
+       if (!priv->ack_buf)
+               goto err_priv;
+
+       memcpy(priv->ack_buf, nexio_ack_pkt, sizeof(nexio_ack_pkt));
+
+       priv->ack = usb_alloc_urb(0, GFP_KERNEL);
+       if (!priv->ack) {
+               dbg("%s - usb_alloc_urb failed: usbtouch->ack", __func__);
+               goto err_ack_buf;
+       }
+
+       usb_fill_bulk_urb(priv->ack, dev, usb_sndbulkpipe(dev, output_ep),
+                         priv->ack_buf, sizeof(nexio_ack_pkt),
+                         nexio_ack_complete, usbtouch);
+       ret = 0;
+       goto out_buf;
+
+err_ack_buf:
+       kfree(priv->ack_buf);
+err_priv:
+       kfree(priv);
+out_buf:
+       kfree(buf);
+       return ret;
+}
+
+static void nexio_exit(struct usbtouch_usb *usbtouch)
+{
+       struct nexio_priv *priv = usbtouch->priv;
+
+       usb_kill_urb(priv->ack);
+       usb_free_urb(priv->ack);
+       kfree(priv->ack_buf);
+       kfree(priv);
+}
+
+static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt)
+{
+       int x, y, begin_x, begin_y, end_x, end_y, w, h, ret;
+       struct nexio_touch_packet *packet = (void *) pkt;
+       struct nexio_priv *priv = usbtouch->priv;
+
+       /* got touch data? */
+       if ((pkt[0] & 0xe0) != 0xe0)
+               return 0;
+
+       /* send ACK */
+       ret = usb_submit_urb(priv->ack, GFP_ATOMIC);
+
+       if (!usbtouch->type->max_xc) {
+               usbtouch->type->max_xc = 2 * be16_to_cpu(packet->x_len);
+               input_set_abs_params(usbtouch->input, ABS_X, 0,
+                                    2 * be16_to_cpu(packet->x_len), 0, 0);
+               usbtouch->type->max_yc = 2 * be16_to_cpu(packet->y_len);
+               input_set_abs_params(usbtouch->input, ABS_Y, 0,
+                                    2 * be16_to_cpu(packet->y_len), 0, 0);
+       }
+       /*
+        * The device reports state of IR sensors on X and Y axes.
+        * Each byte represents "darkness" percentage (0-100) of one element.
+        * 17" touchscreen reports only 64 x 52 bytes so the resolution is low.
+        * This also means that there's a limited multi-touch capability but
+        * it's disabled (and untested) here as there's no X driver for that.
+        */
+       begin_x = end_x = begin_y = end_y = -1;
+       for (x = 0; x < be16_to_cpu(packet->x_len); x++) {
+               if (begin_x == -1 && packet->data[x] > NEXIO_THRESHOLD) {
+                       begin_x = x;
+                       continue;
+               }
+               if (end_x == -1 && begin_x != -1 && packet->data[x] < NEXIO_THRESHOLD) {
+                       end_x = x - 1;
+                       for (y = be16_to_cpu(packet->x_len);
+                            y < be16_to_cpu(packet->data_len); y++) {
+                               if (begin_y == -1 && packet->data[y] > NEXIO_THRESHOLD) {
+                                       begin_y = y - be16_to_cpu(packet->x_len);
+                                       continue;
+                               }
+                               if (end_y == -1 &&
+                                   begin_y != -1 && packet->data[y] < NEXIO_THRESHOLD) {
+                                       end_y = y - 1 - be16_to_cpu(packet->x_len);
+                                       w = end_x - begin_x;
+                                       h = end_y - begin_y;
+#if 0
+                                       /* multi-touch */
+                                       input_report_abs(usbtouch->input,
+                                                   ABS_MT_TOUCH_MAJOR, max(w,h));
+                                       input_report_abs(usbtouch->input,
+                                                   ABS_MT_TOUCH_MINOR, min(x,h));
+                                       input_report_abs(usbtouch->input,
+                                                   ABS_MT_POSITION_X, 2*begin_x+w);
+                                       input_report_abs(usbtouch->input,
+                                                   ABS_MT_POSITION_Y, 2*begin_y+h);
+                                       input_report_abs(usbtouch->input,
+                                                   ABS_MT_ORIENTATION, w > h);
+                                       input_mt_sync(usbtouch->input);
+#endif
+                                       /* single touch */
+                                       usbtouch->x = 2 * begin_x + w;
+                                       usbtouch->y = 2 * begin_y + h;
+                                       usbtouch->touch = packet->flags & 0x01;
+                                       begin_y = end_y = -1;
+                                       return 1;
+                               }
+                       }
+                       begin_x = end_x = -1;
+               }
+
+       }
+       return 0;
+}
+#endif
+
+
 /*****************************************************************************
  * the different device descriptors
  */
@@ -873,6 +1110,16 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
                .read_data      = tc5uh_read_data,
        },
 #endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_NEXIO
+       [DEVTYPE_NEXIO] = {
+               .rept_size      = 128,
+               .irq_always     = true,
+               .read_data      = nexio_read_data,
+               .init           = nexio_init,
+               .exit           = nexio_exit,
+       },
+#endif
 };
 
 
@@ -998,6 +1245,7 @@ static void usbtouch_irq(struct urb *urb)
        case -ECONNRESET:
        case -ENOENT:
        case -ESHUTDOWN:
+       case -EPIPE:
                /* this urb is terminated, clean up */
                dbg("%s - urb shutting down with status: %d",
                    __func__, urb->status);
@@ -1021,7 +1269,7 @@ static int usbtouch_open(struct input_dev *input)
 {
        struct usbtouch_usb *usbtouch = input_get_drvdata(input);
 
-       usbtouch->irq->dev = usbtouch->udev;
+       usbtouch->irq->dev = interface_to_usbdev(usbtouch->interface);
 
        if (!usbtouch->type->irq_always) {
                if (usb_submit_urb(usbtouch->irq, GFP_KERNEL))
@@ -1048,13 +1296,23 @@ static void usbtouch_free_buffers(struct usb_device *udev,
        kfree(usbtouch->buffer);
 }
 
+static struct usb_endpoint_descriptor *
+usbtouch_get_input_endpoint(struct usb_host_interface *interface)
+{
+       int i;
+
+       for (i = 0; i < interface->desc.bNumEndpoints; i++)
+               if (usb_endpoint_dir_in(&interface->endpoint[i].desc))
+                       return &interface->endpoint[i].desc;
+
+       return NULL;
+}
 
 static int usbtouch_probe(struct usb_interface *intf,
                          const struct usb_device_id *id)
 {
        struct usbtouch_usb *usbtouch;
        struct input_dev *input_dev;
-       struct usb_host_interface *interface;
        struct usb_endpoint_descriptor *endpoint;
        struct usb_device *udev = interface_to_usbdev(intf);
        struct usbtouch_device_info *type;
@@ -1064,8 +1322,9 @@ static int usbtouch_probe(struct usb_interface *intf,
        if (id->driver_info == DEVTYPE_IGNORE)
                return -ENODEV;
 
-       interface = intf->cur_altsetting;
-       endpoint = &interface->endpoint[0].desc;
+       endpoint = usbtouch_get_input_endpoint(intf->cur_altsetting);
+       if (!endpoint)
+               return -ENXIO;
 
        usbtouch = kzalloc(sizeof(struct usbtouch_usb), GFP_KERNEL);
        input_dev = input_allocate_device();
@@ -1094,7 +1353,7 @@ static int usbtouch_probe(struct usb_interface *intf,
                goto out_free_buffers;
        }
 
-       usbtouch->udev = udev;
+       usbtouch->interface = intf;
        usbtouch->input = input_dev;
 
        if (udev->manufacturer)
@@ -1133,12 +1392,18 @@ static int usbtouch_probe(struct usb_interface *intf,
                input_set_abs_params(input_dev, ABS_PRESSURE, type->min_press,
                                     type->max_press, 0, 0);
 
-       usb_fill_int_urb(usbtouch->irq, usbtouch->udev,
-                        usb_rcvintpipe(usbtouch->udev, endpoint->bEndpointAddress),
+       if (usb_endpoint_type(endpoint) == USB_ENDPOINT_XFER_INT)
+               usb_fill_int_urb(usbtouch->irq, udev,
+                        usb_rcvintpipe(udev, endpoint->bEndpointAddress),
                         usbtouch->data, type->rept_size,
                         usbtouch_irq, usbtouch, endpoint->bInterval);
+       else
+               usb_fill_bulk_urb(usbtouch->irq, udev,
+                        usb_rcvbulkpipe(udev, endpoint->bEndpointAddress),
+                        usbtouch->data, type->rept_size,
+                        usbtouch_irq, usbtouch);
 
-       usbtouch->irq->dev = usbtouch->udev;
+       usbtouch->irq->dev = udev;
        usbtouch->irq->transfer_dma = usbtouch->data_dma;
        usbtouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
@@ -1147,23 +1412,37 @@ static int usbtouch_probe(struct usb_interface *intf,
                err = type->init(usbtouch);
                if (err) {
                        dbg("%s - type->init() failed, err: %d", __func__, err);
-                       goto out_free_buffers;
+                       goto out_free_urb;
                }
        }
 
        err = input_register_device(usbtouch->input);
        if (err) {
                dbg("%s - input_register_device failed, err: %d", __func__, err);
-               goto out_free_buffers;
+               goto out_do_exit;
        }
 
        usb_set_intfdata(intf, usbtouch);
 
-       if (usbtouch->type->irq_always)
-               usb_submit_urb(usbtouch->irq, GFP_KERNEL);
+       if (usbtouch->type->irq_always) {
+               err = usb_submit_urb(usbtouch->irq, GFP_KERNEL);
+               if (err) {
+                       err("%s - usb_submit_urb failed with result: %d",
+                           __func__, err);
+                       goto out_unregister_input;
+               }
+       }
 
        return 0;
 
+out_unregister_input:
+       input_unregister_device(input_dev);
+       input_dev = NULL;
+out_do_exit:
+       if (type->exit)
+               type->exit(usbtouch);
+out_free_urb:
+       usb_free_urb(usbtouch->irq);
 out_free_buffers:
        usbtouch_free_buffers(udev, usbtouch);
 out_free:
@@ -1186,6 +1465,8 @@ static void usbtouch_disconnect(struct usb_interface *intf)
        /* this will stop IO via close */
        input_unregister_device(usbtouch->input);
        usb_free_urb(usbtouch->irq);
+       if (usbtouch->type->exit)
+               usbtouch->type->exit(usbtouch);
        usbtouch_free_buffers(interface_to_usbdev(intf), usbtouch);
        kfree(usbtouch);
 }
index eca54dbdf4937386c179d928b22e90a739bbc54c..0488498676436938a7336fcb7eb1b8fa34bbc6fe 100644 (file)
@@ -118,6 +118,9 @@ static int wm97xx_acc_pen_down(struct wm97xx *wm)
                if (pressure)
                        p = MODR;
 
+               dev_dbg(wm->dev, "Raw coordinates: x=%x, y=%x, p=%x\n",
+                       x, y, p);
+
                /* are samples valid */
                if ((x & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_X ||
                    (y & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_Y ||
index c721c0a23eb831d20672e16120b3278e8901f428..d30436fee4760f02486e952e9468af375432161c 100644 (file)
@@ -321,7 +321,7 @@ InitWait:
        }
 }
 
-static struct xenbus_device_id xenkbd_ids[] = {
+static const struct xenbus_device_id xenkbd_ids[] = {
        { "vkbd" },
        { "" }
 };
index 3d906833948d23862d468938e9b4d0ffb0233675..fd85bde283a034b7e4612fd7582e3c81d856dfd7 100644 (file)
@@ -171,8 +171,8 @@ config INPUT_ADBHID
          If unsure, say Y.
 
 config MAC_EMUMOUSEBTN
-       bool "Support for mouse button 2+3 emulation"
-       select INPUT
+       tristate "Support for mouse button 2+3 emulation"
+       depends on SYSCTL && INPUT
        help
          This provides generic support for emulating the 2nd and 3rd mouse
          button with keypresses.  If you say Y here, the emulation is still
@@ -184,6 +184,9 @@ config MAC_EMUMOUSEBTN
 
          If you have an Apple machine with a 1-button mouse, say Y here.
 
+         To compile this driver as a module, choose M here: the
+         module will be called mac_hid.
+
 config THERM_WINDTUNNEL
        tristate "Support for thermal management on Windtunnel G4s"
        depends on I2C && I2C_POWERMAC && PPC_PMAC && !PPC_PMAC64
index 7b4ef5bb556b9607c78c9d812f2dba8e888de6b4..e943d2a29253d53b60d35c08cfe89e83902508ac 100644 (file)
 #include <linux/sysctl.h>
 #include <linux/input.h>
 #include <linux/module.h>
-#include <linux/kbd_kern.h>
 
+MODULE_LICENSE("GPL");
 
-static struct input_dev *emumousebtn;
-static int emumousebtn_input_register(void);
 static int mouse_emulate_buttons;
 static int mouse_button2_keycode = KEY_RIGHTCTRL;      /* right control key */
 static int mouse_button3_keycode = KEY_RIGHTALT;       /* right option key */
-static int mouse_last_keycode;
 
-#if defined(CONFIG_SYSCTL)
+static struct input_dev *mac_hid_emumouse_dev;
+
+static int mac_hid_create_emumouse(void)
+{
+       static struct lock_class_key mac_hid_emumouse_dev_event_class;
+       static struct lock_class_key mac_hid_emumouse_dev_mutex_class;
+       int err;
+
+       mac_hid_emumouse_dev = input_allocate_device();
+       if (!mac_hid_emumouse_dev)
+               return -ENOMEM;
+
+       lockdep_set_class(&mac_hid_emumouse_dev->event_lock,
+                         &mac_hid_emumouse_dev_event_class);
+       lockdep_set_class(&mac_hid_emumouse_dev->mutex,
+                         &mac_hid_emumouse_dev_mutex_class);
+
+       mac_hid_emumouse_dev->name = "Macintosh mouse button emulation";
+       mac_hid_emumouse_dev->id.bustype = BUS_ADB;
+       mac_hid_emumouse_dev->id.vendor = 0x0001;
+       mac_hid_emumouse_dev->id.product = 0x0001;
+       mac_hid_emumouse_dev->id.version = 0x0100;
+
+       mac_hid_emumouse_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+       mac_hid_emumouse_dev->keybit[BIT_WORD(BTN_MOUSE)] =
+               BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
+       mac_hid_emumouse_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
+
+       err = input_register_device(mac_hid_emumouse_dev);
+       if (err) {
+               input_free_device(mac_hid_emumouse_dev);
+               mac_hid_emumouse_dev = NULL;
+               return err;
+       }
+
+       return 0;
+}
+
+static void mac_hid_destroy_emumouse(void)
+{
+       input_unregister_device(mac_hid_emumouse_dev);
+       mac_hid_emumouse_dev = NULL;
+}
+
+static bool mac_hid_emumouse_filter(struct input_handle *handle,
+                                   unsigned int type, unsigned int code,
+                                   int value)
+{
+       unsigned int btn;
+
+       if (type != EV_KEY)
+               return false;
+
+       if (code == mouse_button2_keycode)
+               btn = BTN_MIDDLE;
+       else if (code == mouse_button3_keycode)
+               btn = BTN_RIGHT;
+       else
+               return false;
+
+       input_report_key(mac_hid_emumouse_dev, btn, value);
+       input_sync(mac_hid_emumouse_dev);
+
+       return true;
+}
+
+static int mac_hid_emumouse_connect(struct input_handler *handler,
+                                   struct input_dev *dev,
+                                   const struct input_device_id *id)
+{
+       struct input_handle *handle;
+       int error;
+
+       /* Don't bind to ourselves */
+       if (dev == mac_hid_emumouse_dev)
+               return -ENODEV;
+
+       handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
+       if (!handle)
+               return -ENOMEM;
+
+       handle->dev = dev;
+       handle->handler = handler;
+       handle->name = "mac-button-emul";
+
+       error = input_register_handle(handle);
+       if (error) {
+               printk(KERN_ERR
+                       "mac_hid: Failed to register button emulation handle, "
+                       "error %d\n", error);
+               goto err_free;
+       }
+
+       error = input_open_device(handle);
+       if (error) {
+               printk(KERN_ERR
+                       "mac_hid: Failed to open input device, error %d\n",
+                       error);
+               goto err_unregister;
+       }
+
+       return 0;
+
+ err_unregister:
+       input_unregister_handle(handle);
+ err_free:
+       kfree(handle);
+       return error;
+}
+
+static void mac_hid_emumouse_disconnect(struct input_handle *handle)
+{
+       input_close_device(handle);
+       input_unregister_handle(handle);
+       kfree(handle);
+}
+
+static const struct input_device_id mac_hid_emumouse_ids[] = {
+       {
+               .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+               .evbit = { BIT_MASK(EV_KEY) },
+       },
+       { },
+};
+
+MODULE_DEVICE_TABLE(input, mac_hid_emumouse_ids);
+
+static struct input_handler mac_hid_emumouse_handler = {
+       .filter         = mac_hid_emumouse_filter,
+       .connect        = mac_hid_emumouse_connect,
+       .disconnect     = mac_hid_emumouse_disconnect,
+       .name           = "mac-button-emul",
+       .id_table       = mac_hid_emumouse_ids,
+};
+
+static int mac_hid_start_emulation(void)
+{
+       int err;
+
+       err = mac_hid_create_emumouse();
+       if (err)
+               return err;
+
+       err = input_register_handler(&mac_hid_emumouse_handler);
+       if (err) {
+               mac_hid_destroy_emumouse();
+               return err;
+       }
+
+       return 0;
+}
+
+static void mac_hid_stop_emulation(void)
+{
+       input_unregister_handler(&mac_hid_emumouse_handler);
+       mac_hid_destroy_emumouse();
+}
+
+static int mac_hid_toggle_emumouse(ctl_table *table, int write,
+                                  void __user *buffer, size_t *lenp,
+                                  loff_t *ppos)
+{
+       int *valp = table->data;
+       int old_val = *valp;
+       int rc;
+
+       rc = proc_dointvec(table, write, buffer, lenp, ppos);
+
+       if (rc == 0 && write && *valp != old_val) {
+               if (*valp == 1)
+                       rc = mac_hid_start_emulation();
+               else if (*valp == 0)
+                       mac_hid_stop_emulation();
+               else
+                       rc = -EINVAL;
+       }
+
+       /* Restore the old value in case of error */
+       if (rc)
+               *valp = old_val;
+
+       return rc;
+}
+
 /* file(s) in /proc/sys/dev/mac_hid */
 static ctl_table mac_hid_files[] = {
        {
@@ -31,7 +211,7 @@ static ctl_table mac_hid_files[] = {
                .data           = &mouse_emulate_buttons,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec,
+               .proc_handler   = mac_hid_toggle_emumouse,
        },
        {
                .procname       = "mouse_button2_keycode",
@@ -74,75 +254,21 @@ static ctl_table mac_hid_root_dir[] = {
 
 static struct ctl_table_header *mac_hid_sysctl_header;
 
-#endif /* endif CONFIG_SYSCTL */
-
-int mac_hid_mouse_emulate_buttons(int caller, unsigned int keycode, int down)
-{
-       switch (caller) {
-       case 1:
-               /* Called from keyboard.c */
-               if (mouse_emulate_buttons
-                   && (keycode == mouse_button2_keycode
-                       || keycode == mouse_button3_keycode)) {
-                       if (mouse_emulate_buttons == 1) {
-                               input_report_key(emumousebtn,
-                                                keycode == mouse_button2_keycode ? BTN_MIDDLE : BTN_RIGHT,
-                                                down);
-                               input_sync(emumousebtn);
-                               return 1;
-                       }
-                       mouse_last_keycode = down ? keycode : 0;
-               }
-               break;
-       }
-       return 0;
-}
-
-static struct lock_class_key emumousebtn_event_class;
-static struct lock_class_key emumousebtn_mutex_class;
-
-static int emumousebtn_input_register(void)
+static int __init mac_hid_init(void)
 {
-       int ret;
-
-       emumousebtn = input_allocate_device();
-       if (!emumousebtn)
+       mac_hid_sysctl_header = register_sysctl_table(mac_hid_root_dir);
+       if (!mac_hid_sysctl_header)
                return -ENOMEM;
 
-       lockdep_set_class(&emumousebtn->event_lock, &emumousebtn_event_class);
-       lockdep_set_class(&emumousebtn->mutex, &emumousebtn_mutex_class);
-
-       emumousebtn->name = "Macintosh mouse button emulation";
-       emumousebtn->id.bustype = BUS_ADB;
-       emumousebtn->id.vendor = 0x0001;
-       emumousebtn->id.product = 0x0001;
-       emumousebtn->id.version = 0x0100;
-
-       emumousebtn->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
-       emumousebtn->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
-               BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
-       emumousebtn->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
-
-       ret = input_register_device(emumousebtn);
-       if (ret)
-               input_free_device(emumousebtn);
-
-       return ret;
+       return 0;
 }
+module_init(mac_hid_init);
 
-static int __init mac_hid_init(void)
+static void __exit mac_hid_exit(void)
 {
-       int err;
-
-       err = emumousebtn_input_register();
-       if (err)
-               return err;
-
-#if defined(CONFIG_SYSCTL)
-       mac_hid_sysctl_header = register_sysctl_table(mac_hid_root_dir);
-#endif /* CONFIG_SYSCTL */
+       unregister_sysctl_table(mac_hid_sysctl_header);
 
-       return 0;
+       if (mouse_emulate_buttons)
+               mac_hid_stop_emulation();
 }
-
-device_initcall(mac_hid_init);
+module_exit(mac_hid_exit);
index 00435bd206990416c21cad98b549483b123a99c8..af2d39d603c74446c3c792d6bdc3ee334067d639 100644 (file)
@@ -177,7 +177,7 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks)
                 */
                if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
                    queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9))
-                       blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
+                       blk_queue_max_hw_sectors(mddev->queue, PAGE_SIZE>>9);
 
                conf->array_sectors += rdev->sectors;
                cnt++;
index 32a662fc55c95d5f08de09362f85d0d6ab0917e3..4b323f45ad74a357432c6115822f4cc5347ef0c3 100644 (file)
@@ -308,7 +308,7 @@ static int multipath_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
                 */
                        if (q->merge_bvec_fn &&
                            queue_max_sectors(q) > (PAGE_SIZE>>9))
-                               blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
+                               blk_queue_max_hw_sectors(mddev->queue, PAGE_SIZE>>9);
 
                        conf->working_disks++;
                        mddev->degraded--;
@@ -478,7 +478,7 @@ static int multipath_run (mddev_t *mddev)
                 * a merge_bvec_fn to be involved in multipath */
                if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
                    queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9))
-                       blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
+                       blk_queue_max_hw_sectors(mddev->queue, PAGE_SIZE>>9);
 
                if (!test_bit(Faulty, &rdev->flags))
                        conf->working_disks++;
index 77605cdceaf179ce1a5ce15d9bf50d4239efb91e..a1f7147b757fd6f79231ef52721b587fbbfe4432 100644 (file)
@@ -182,7 +182,7 @@ static int create_strip_zones(mddev_t *mddev)
 
                if (rdev1->bdev->bd_disk->queue->merge_bvec_fn &&
                    queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9))
-                       blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
+                       blk_queue_max_hw_sectors(mddev->queue, PAGE_SIZE>>9);
 
                if (!smallest || (rdev1->sectors < smallest->sectors))
                        smallest = rdev1;
@@ -325,7 +325,7 @@ static int raid0_run(mddev_t *mddev)
        }
        if (md_check_no_bitmap(mddev))
                return -EINVAL;
-       blk_queue_max_sectors(mddev->queue, mddev->chunk_sectors);
+       blk_queue_max_hw_sectors(mddev->queue, mddev->chunk_sectors);
        mddev->queue->queue_lock = &mddev->queue->__queue_lock;
 
        ret = create_strip_zones(mddev);
index 859bd3ffe4351bad9204aa04e906e751a788c64a..5a06122abd3bbd9d49a121675e37dd95bd5ba4ff 100644 (file)
@@ -1158,7 +1158,7 @@ static int raid1_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
                         */
                        if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
                            queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9))
-                               blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
+                               blk_queue_max_hw_sectors(mddev->queue, PAGE_SIZE>>9);
 
                        p->head_position = 0;
                        rdev->raid_disk = mirror;
@@ -2103,7 +2103,7 @@ static int run(mddev_t *mddev)
                 */
                if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
                    queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9))
-                       blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
+                       blk_queue_max_hw_sectors(mddev->queue, PAGE_SIZE>>9);
        }
 
        mddev->degraded = 0;
index d119b7b75e71ffabe5863b0b3463b7a66304f831..7584f9ab9bcfedf159bf94fd1238f9321d14e866 100644 (file)
@@ -1161,7 +1161,7 @@ static int raid10_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
                         */
                        if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
                            queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9))
-                               blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
+                               blk_queue_max_hw_sectors(mddev->queue, PAGE_SIZE>>9);
 
                        p->head_position = 0;
                        rdev->raid_disk = mirror;
@@ -2260,7 +2260,7 @@ static int run(mddev_t *mddev)
                 */
                if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
                    queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9))
-                       blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
+                       blk_queue_max_hw_sectors(mddev->queue, PAGE_SIZE>>9);
 
                disk->head_position = 0;
        }
index ceb24afdc147aada31741b10213443375617257f..509c8f3dd9a565f35f1e53ed7d8a0987e8b05d74 100644 (file)
@@ -3739,7 +3739,7 @@ static int bio_fits_rdev(struct bio *bi)
        if ((bi->bi_size>>9) > queue_max_sectors(q))
                return 0;
        blk_recount_segments(q, bi);
-       if (bi->bi_phys_segments > queue_max_phys_segments(q))
+       if (bi->bi_phys_segments > queue_max_segments(q))
                return 0;
 
        if (q->merge_bvec_fn)
index bd83fa0a4970fb13a5ddef788d1c68a5a7b21300..972b87069d55aad0e6d27eba6b7fbbba55064598 100644 (file)
@@ -1226,9 +1226,8 @@ static int mspro_block_init_disk(struct memstick_dev *card)
        blk_queue_prep_rq(msb->queue, mspro_block_prepare_req);
 
        blk_queue_bounce_limit(msb->queue, limit);
-       blk_queue_max_sectors(msb->queue, MSPRO_BLOCK_MAX_PAGES);
-       blk_queue_max_phys_segments(msb->queue, MSPRO_BLOCK_MAX_SEGS);
-       blk_queue_max_hw_segments(msb->queue, MSPRO_BLOCK_MAX_SEGS);
+       blk_queue_max_hw_sectors(msb->queue, MSPRO_BLOCK_MAX_PAGES);
+       blk_queue_max_segments(msb->queue, MSPRO_BLOCK_MAX_SEGS);
        blk_queue_max_segment_size(msb->queue,
                                   MSPRO_BLOCK_MAX_PAGES * msb->page_size);
 
index e39986a7827399dbe607ebe70d140fc615d12af6..2658b1484a2c7ba0480d99ad413087fb70cf523b 100644 (file)
@@ -1065,9 +1065,8 @@ static int i2o_block_probe(struct device *dev)
        queue = gd->queue;
        queue->queuedata = i2o_blk_dev;
 
-       blk_queue_max_phys_segments(queue, I2O_MAX_PHYS_SEGMENTS);
-       blk_queue_max_sectors(queue, max_sectors);
-       blk_queue_max_hw_segments(queue, i2o_sg_tablesize(c, body_size));
+       blk_queue_max_hw_sectors(queue, max_sectors);
+       blk_queue_max_segments(queue, i2o_sg_tablesize(c, body_size));
 
        osm_debug("max sectors = %d\n", queue->max_sectors);
        osm_debug("phys segments = %d\n", queue->max_phys_segments);
index 2a7606534196e7849f8cac4b07bbb9751a21484e..19a930d06241ad28a459e28d03bfbabd287f3e88 100644 (file)
 #define twl_has_watchdog()        false
 #endif
 
-#if defined(CONFIG_TWL4030_CODEC) || defined(CONFIG_TWL4030_CODEC_MODULE)
+#if defined(CONFIG_TWL4030_CODEC) || defined(CONFIG_TWL4030_CODEC_MODULE) ||\
+       defined(CONFIG_SND_SOC_TWL6030) || defined(CONFIG_SND_SOC_TWL6030_MODULE)
 #define twl_has_codec()        true
 #else
 #define twl_has_codec()        false
@@ -711,8 +712,19 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
                        return PTR_ERR(child);
        }
 
-       if (twl_has_codec() && pdata->codec) {
-               child = add_child(1, "twl4030_codec",
+       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",
+                               pdata->codec, sizeof(*pdata->codec),
+                               false, 0, 0);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+       }
+
+       /* Phoenix*/
+       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, "twl6030_codec",
                                pdata->codec, sizeof(*pdata->codec),
                                false, 0, 0);
                if (IS_ERR(child))
index c5a7a855f4b1c5f0a8ad7472a8f7896127d03ea8..381fe032caa129039c89da492a0b092f5540aed1 100644 (file)
@@ -154,9 +154,8 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
 
                if (mq->bounce_buf) {
                        blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY);
-                       blk_queue_max_sectors(mq->queue, bouncesz / 512);
-                       blk_queue_max_phys_segments(mq->queue, bouncesz / 512);
-                       blk_queue_max_hw_segments(mq->queue, bouncesz / 512);
+                       blk_queue_max_hw_sectors(mq->queue, bouncesz / 512);
+                       blk_queue_max_segments(mq->queue, bouncesz / 512);
                        blk_queue_max_segment_size(mq->queue, bouncesz);
 
                        mq->sg = kmalloc(sizeof(struct scatterlist),
@@ -180,10 +179,9 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
 
        if (!mq->bounce_buf) {
                blk_queue_bounce_limit(mq->queue, limit);
-               blk_queue_max_sectors(mq->queue,
+               blk_queue_max_hw_sectors(mq->queue,
                        min(host->max_blk_count, host->max_req_size / 512));
-               blk_queue_max_phys_segments(mq->queue, host->max_phys_segs);
-               blk_queue_max_hw_segments(mq->queue, host->max_hw_segs);
+               blk_queue_max_segments(mq->queue, host->max_hw_segs);
                blk_queue_max_segment_size(mq->queue, host->max_seg_size);
 
                mq->sg = kmalloc(sizeof(struct scatterlist) *
index 90d168ad03b6ca60574f45c03175b845bb2033b3..84c103a7ee13affecd683762aa9bf5881c174005 100644 (file)
@@ -2,6 +2,7 @@
  *  linux/drivers/mmc/host/mmci.c - ARM PrimeCell MMCI PL180/1 driver
  *
  *  Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
+ *  Copyright (C) 2010 ST-Ericsson AB.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -34,9 +35,6 @@
 
 #define DRIVER_NAME "mmci-pl18x"
 
-#define DBG(host,fmt,args...)  \
-       pr_debug("%s: %s: " fmt, mmc_hostname(host->mmc), __func__ , args)
-
 static unsigned int fmax = 515633;
 
 /*
@@ -105,8 +103,8 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
        void __iomem *base;
        int blksz_bits;
 
-       DBG(host, "blksz %04x blks %04x flags %08x\n",
-           data->blksz, data->blocks, data->flags);
+       dev_dbg(mmc_dev(host->mmc), "blksz %04x blks %04x flags %08x\n",
+               data->blksz, data->blocks, data->flags);
 
        host->data = data;
        host->size = data->blksz;
@@ -155,7 +153,7 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
 {
        void __iomem *base = host->base;
 
-       DBG(host, "op %02x arg %08x flags %08x\n",
+       dev_dbg(mmc_dev(host->mmc), "op %02x arg %08x flags %08x\n",
            cmd->opcode, cmd->arg, cmd->flags);
 
        if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) {
@@ -184,8 +182,20 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
 {
        if (status & MCI_DATABLOCKEND) {
                host->data_xfered += data->blksz;
+#ifdef CONFIG_ARCH_U300
+               /*
+                * On the U300 some signal or other is
+                * badly routed so that a data write does
+                * not properly terminate with a MCI_DATAEND
+                * status flag. This quirk will make writes
+                * work again.
+                */
+               if (data->flags & MMC_DATA_WRITE)
+                       status |= MCI_DATAEND;
+#endif
        }
        if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
+               dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ (status %08x)\n", status);
                if (status & MCI_DATACRCFAIL)
                        data->error = -EILSEQ;
                else if (status & MCI_DATATIMEOUT)
@@ -307,7 +317,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
 
        status = readl(base + MMCISTATUS);
 
-       DBG(host, "irq1 %08x\n", status);
+       dev_dbg(mmc_dev(host->mmc), "irq1 (pio) %08x\n", status);
 
        do {
                unsigned long flags;
@@ -401,7 +411,7 @@ static irqreturn_t mmci_irq(int irq, void *dev_id)
                status &= readl(host->base + MMCIMASK0);
                writel(status, host->base + MMCICLEAR);
 
-               DBG(host, "irq0 %08x\n", status);
+               dev_dbg(mmc_dev(host->mmc), "irq0 (data+cmd) %08x\n", status);
 
                data = host->data;
                if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|
@@ -428,8 +438,8 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
        WARN_ON(host->mrq != NULL);
 
        if (mrq->data && !is_power_of_2(mrq->data->blksz)) {
-               printk(KERN_ERR "%s: Unsupported block size (%d bytes)\n",
-                       mmc_hostname(mmc), mrq->data->blksz);
+               dev_err(mmc_dev(mmc), "unsupported block size (%d bytes)\n",
+                       mrq->data->blksz);
                mrq->cmd->error = -EINVAL;
                mmc_request_done(mmc, mrq);
                return;
@@ -582,8 +592,8 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
 
        host->hw_designer = amba_manf(dev);
        host->hw_revision = amba_rev(dev);
-       DBG(host, "designer ID = 0x%02x\n", host->hw_designer);
-       DBG(host, "revision = 0x%01x\n", host->hw_revision);
+       dev_dbg(mmc_dev(mmc), "designer ID = 0x%02x\n", host->hw_designer);
+       dev_dbg(mmc_dev(mmc), "revision = 0x%01x\n", host->hw_revision);
 
        host->clk = clk_get(&dev->dev, NULL);
        if (IS_ERR(host->clk)) {
@@ -608,7 +618,8 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
                if (ret < 0)
                        goto clk_disable;
                host->mclk = clk_get_rate(host->clk);
-               DBG(host, "eventual mclk rate: %u Hz\n", host->mclk);
+               dev_dbg(mmc_dev(mmc), "eventual mclk rate: %u Hz\n",
+                       host->mclk);
        }
        host->base = ioremap(dev->res.start, resource_size(&dev->res));
        if (!host->base) {
@@ -619,6 +630,8 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
        mmc->ops = &mmci_ops;
        mmc->f_min = (host->mclk + 511) / 512;
        mmc->f_max = min(host->mclk, fmax);
+       dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max);
+
 #ifdef CONFIG_REGULATOR
        /* If we're using the regulator framework, try to fetch a regulator */
        host->vcc = regulator_get(&dev->dev, "vmmc");
@@ -712,7 +725,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
 
        mmc_add_host(mmc);
 
-       printk(KERN_INFO "%s: MMCI rev %x cfg %02x at 0x%016llx irq %d,%d\n",
+       dev_info(&dev->dev, "%s: MMCI rev %x cfg %02x at 0x%016llx irq %d,%d\n",
                mmc_hostname(mmc), amba_rev(dev), amba_config(dev),
                (unsigned long long)dev->res.start, dev->irq[0], dev->irq[1]);
 
index 46af867af85f393bb4caf32b832fadb42e61aed2..7029cd50c458897e1686925bb2aef9da70d82c92 100644 (file)
@@ -932,7 +932,7 @@ config NET_NETX
 
 config TI_DAVINCI_EMAC
        tristate "TI DaVinci EMAC Support"
-       depends on ARM && ARCH_DAVINCI
+       depends on ARM && ( ARCH_DAVINCI || ARCH_OMAP3 )
        select PHYLIB
        help
          This driver supports TI's DaVinci Ethernet .
index 3f5db83c7cbb29d6d1d313f961839ecdf7cd0873..1ac9440eb3fb2daa6bf1c035d36dc37fb459279c 100644 (file)
 #include <linux/bitops.h>
 #include <linux/io.h>
 #include <linux/uaccess.h>
+#include <linux/davinci_emac.h>
 
 #include <asm/irq.h>
 #include <asm/page.h>
 
-#include <mach/emac.h>
-
 static int debug_level;
 module_param(debug_level, int, 0);
 MODULE_PARM_DESC(debug_level, "DaVinci EMAC debug level (NETIF_MSG bits)");
@@ -465,6 +464,7 @@ struct emac_priv {
        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];
        u32 link; /* 1=link on, 0=link off */
@@ -488,6 +488,9 @@ struct emac_priv {
        struct mii_bus *mii_bus;
        struct phy_device *phydev;
        spinlock_t lock;
+       /*platform specific members*/
+       void (*int_enable) (void);
+       void (*int_disable) (void);
 };
 
 /* clock frequency for EMAC */
@@ -495,11 +498,9 @@ static struct clk *emac_clk;
 static unsigned long emac_bus_frequency;
 static unsigned long mdio_max_freq;
 
-/* EMAC internal utility function */
-static inline u32 emac_virt_to_phys(void __iomem *addr)
-{
-       return (u32 __force) io_v2p(addr);
-}
+#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)
@@ -1001,6 +1002,8 @@ static void emac_int_disable(struct emac_priv *priv)
                emac_ctrl_write(EMAC_DM646X_CMRXINTEN, 0x0);
                emac_ctrl_write(EMAC_DM646X_CMTXINTEN, 0x0);
                /* NOTE: Rx Threshold and Misc interrupts are not disabled */
+               if (priv->int_disable)
+                       priv->int_disable();
 
                local_irq_restore(flags);
 
@@ -1020,6 +1023,9 @@ static void emac_int_disable(struct emac_priv *priv)
 static void emac_int_enable(struct emac_priv *priv)
 {
        if (priv->version == EMAC_VERSION_2) {
+               if (priv->int_enable)
+                       priv->int_enable();
+
                emac_ctrl_write(EMAC_DM646X_CMRXINTEN, 0xff);
                emac_ctrl_write(EMAC_DM646X_CMTXINTEN, 0xff);
 
@@ -1301,7 +1307,7 @@ static int emac_tx_bdproc(struct emac_priv *priv, u32 ch, u32 budget)
        curr_bd = txch->active_queue_head;
        if (NULL == curr_bd) {
                emac_write(EMAC_TXCP(ch),
-                          emac_virt_to_phys(txch->last_hw_bdprocessed));
+                          emac_virt_to_phys(txch->last_hw_bdprocessed, priv));
                txch->no_active_pkts++;
                spin_unlock_irqrestore(&priv->tx_lock, flags);
                return 0;
@@ -1311,7 +1317,7 @@ static int emac_tx_bdproc(struct emac_priv *priv, u32 ch, u32 budget)
        while ((curr_bd) &&
              ((frame_status & EMAC_CPPI_OWNERSHIP_BIT) == 0) &&
              (pkts_processed < budget)) {
-               emac_write(EMAC_TXCP(ch), emac_virt_to_phys(curr_bd));
+               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 */
@@ -1398,7 +1404,7 @@ static int emac_send(struct emac_priv *priv, struct emac_netpktobj *pkt, u32 ch)
                txch->active_queue_tail = curr_bd;
                if (1 != txch->queue_active) {
                        emac_write(EMAC_TXHDP(ch),
-                                       emac_virt_to_phys(curr_bd));
+                                       emac_virt_to_phys(curr_bd, priv));
                        txch->queue_active = 1;
                }
                ++txch->queue_reinit;
@@ -1410,10 +1416,11 @@ static int emac_send(struct emac_priv *priv, struct emac_netpktobj *pkt, u32 ch)
                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);
+               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));
+                       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;
@@ -1603,7 +1610,8 @@ static int emac_init_rxch(struct emac_priv *priv, u32 ch, char *param)
                }
 
                /* populate the hardware descriptor */
-               curr_bd->h_next = emac_virt_to_phys(rxch->active_queue_head);
+               curr_bd->h_next = emac_virt_to_phys(rxch->active_queue_head,
+                               priv);
                /* FIXME buff_ptr = dma_map_single(... data_ptr ...) */
                curr_bd->buff_ptr = virt_to_phys(curr_bd->data_ptr);
                curr_bd->off_b_len = rxch->buf_size;
@@ -1878,7 +1886,7 @@ static void emac_addbd_to_rx_queue(struct emac_priv *priv, u32 ch,
                rxch->active_queue_tail = curr_bd;
                if (0 != rxch->queue_active) {
                        emac_write(EMAC_RXHDP(ch),
-                                  emac_virt_to_phys(rxch->active_queue_head));
+                          emac_virt_to_phys(rxch->active_queue_head, priv));
                        rxch->queue_active = 1;
                }
        } else {
@@ -1889,11 +1897,11 @@ static void emac_addbd_to_rx_queue(struct emac_priv *priv, u32 ch,
                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);
+               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));
+                                       emac_virt_to_phys(curr_bd, priv));
                        frame_status &= ~(EMAC_CPPI_EOQ_BIT);
                        tail_bd->mode = frame_status;
                        ++rxch->end_of_queue_add;
@@ -1986,7 +1994,7 @@ static int emac_rx_bdproc(struct emac_priv *priv, u32 ch, u32 budget)
                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));
+               emac_write(EMAC_RXCP(ch), emac_virt_to_phys(curr_bd, priv));
                ++rxch->processed_bd;
                last_bd = curr_bd;
                curr_bd = last_bd->next;
@@ -1997,7 +2005,7 @@ static int emac_rx_bdproc(struct emac_priv *priv, u32 ch, u32 budget)
                        if (curr_bd) {
                                ++rxch->mis_queued_packets;
                                emac_write(EMAC_RXHDP(ch),
-                                          emac_virt_to_phys(curr_bd));
+                                          emac_virt_to_phys(curr_bd, priv));
                        } else {
                                ++rxch->end_of_queue;
                                rxch->queue_active = 0;
@@ -2098,7 +2106,7 @@ static int emac_hw_enable(struct emac_priv *priv)
                emac_write(EMAC_RXINTMASKSET, BIT(ch));
                rxch->queue_active = 1;
                emac_write(EMAC_RXHDP(ch),
-                          emac_virt_to_phys(rxch->active_queue_head));
+                          emac_virt_to_phys(rxch->active_queue_head, priv));
        }
 
        /* Enable MII */
@@ -2659,6 +2667,9 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
        priv->phy_mask = pdata->phy_mask;
        priv->rmii_en = pdata->rmii_en;
        priv->version = pdata->version;
+       priv->int_enable = pdata->interrupt_enable;
+       priv->int_disable = pdata->interrupt_disable;
+
        emac_dev = &ndev->dev;
        /* Get EMAC platform data */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -2690,6 +2701,12 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
        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;
+
        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (!res) {
                dev_err(emac_dev, "DaVinci EMAC: Error getting irq res\n");
index c0c73913833df3f401499ac2ec6f867ce388404f..2e7a3bf13824945ac18ff54187146585e03d31f6 100644 (file)
@@ -354,7 +354,7 @@ static struct pci_platform_pm_ops acpi_pci_platform_pm = {
 static int acpi_pci_find_device(struct device *dev, acpi_handle *handle)
 {
        struct pci_dev * pci_dev;
-       acpi_integer    addr;
+       u64     addr;
 
        pci_dev = to_pci_dev(dev);
        /* Please ref to ACPI spec for the syntax of _ADR */
index bf32f07c4efb7a68504c5348eb9b908281665894..4fe36d2e104930cc99cc7014b27614277d75c9f8 100644 (file)
@@ -101,9 +101,17 @@ static void __assign_resources_sorted(struct resource_list *head,
        for (list = head->next; list;) {
                res = list->res;
                idx = res - &list->dev->resource[0];
+
                if (pci_assign_resource(list->dev, idx)) {
-                       if (fail_head && !pci_is_root_bus(list->dev->bus))
-                               add_to_failed_list(fail_head, list->dev, res);
+                       if (fail_head && !pci_is_root_bus(list->dev->bus)) {
+                               /*
+                                * if the failed res is for ROM BAR, and it will
+                                * be enabled later, don't add it to the list
+                                */
+                               if (!((idx == PCI_ROM_RESOURCE) &&
+                                     (!(res->flags & IORESOURCE_ROM_ENABLE))))
+                                       add_to_failed_list(fail_head, list->dev, res);
+                       }
                        res->start = 0;
                        res->end = 0;
                        res->flags = 0;
index a350418e87ea18cf2f5812df7191cbed2d535e82..944068611919394eaa42c6337e96b2e1e02b9fee 100644 (file)
@@ -57,7 +57,7 @@ static struct acpi_driver toshiba_bt_rfkill_driver = {
 static int toshiba_bluetooth_enable(acpi_handle handle)
 {
        acpi_status res1, res2;
-       acpi_integer result;
+       u64 result;
 
        /*
         * Query ACPI to verify RFKill switch is set to 'on'.
@@ -95,7 +95,7 @@ static int toshiba_bt_resume(struct acpi_device *device)
 static int toshiba_bt_rfkill_add(struct acpi_device *device)
 {
        acpi_status status;
-       acpi_integer bt_present;
+       u64 bt_present;
        int result = -ENODEV;
 
        /*
index b104302fea0a1e9dbc4a91f82290a185ad244e00..09e9918c69c145820f92e19fc2fc76947c7321bc 100644 (file)
@@ -796,7 +796,7 @@ static __init acpi_status parse_wdg(acpi_handle handle)
  */
 static acpi_status
 acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address,
-                     u32 bits, acpi_integer * value,
+                     u32 bits, u64 *value,
                      void *handler_context, void *region_context)
 {
        int result = 0, i = 0;
@@ -813,7 +813,7 @@ acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address,
 
        if (function == ACPI_READ) {
                result = ec_read(address, &temp);
-               (*value) |= ((acpi_integer)temp) << i;
+               (*value) |= ((u64)temp) << i;
        } else {
                temp = 0xff & ((*value) >> i);
                result = ec_write(address, temp);
index 0264b117893b36eba4616843d0e5a48f10e03721..c256aacfa9542232c121bd6a91a95456a16406c6 100644 (file)
@@ -7,6 +7,9 @@
  *
  * Copyright 2006 (c) MontaVista Software, Inc.
  *
+ * Author: Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
+ * Copyright 2010 (c) ST-Ericsson AB
+ *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version
@@ -18,6 +21,9 @@
 #include <linux/interrupt.h>
 #include <linux/amba/bus.h>
 #include <linux/io.h>
+#include <linux/bcd.h>
+#include <linux/delay.h>
+#include <linux/version.h>
 
 /*
  * Register definitions
 #define        RTC_RIS         0x14    /* Raw interrupt status register */
 #define        RTC_MIS         0x18    /* Masked interrupt status register */
 #define        RTC_ICR         0x1c    /* Interrupt clear register */
+/* ST variants have additional timer functionality */
+#define RTC_TDR                0x20    /* Timer data read register */
+#define RTC_TLR                0x24    /* Timer data load register */
+#define RTC_TCR                0x28    /* Timer control register */
+#define RTC_YDR                0x30    /* Year data read register */
+#define RTC_YMR                0x34    /* Year match register */
+#define RTC_YLR                0x38    /* Year data load register */
+
+#define RTC_CR_CWEN    (1 << 26)       /* Clockwatch enable bit */
+
+#define RTC_TCR_EN     (1 << 1) /* Periodic timer enable bit */
+
+/* Common bit definitions for Interrupt status and control registers */
+#define RTC_BIT_AI     (1 << 0) /* Alarm interrupt bit */
+#define RTC_BIT_PI     (1 << 1) /* Periodic interrupt bit. ST variants only. */
+
+/* Common bit definations for ST v2 for reading/writing time */
+#define RTC_SEC_SHIFT 0
+#define RTC_SEC_MASK (0x3F << RTC_SEC_SHIFT) /* Second [0-59] */
+#define RTC_MIN_SHIFT 6
+#define RTC_MIN_MASK (0x3F << RTC_MIN_SHIFT) /* Minute [0-59] */
+#define RTC_HOUR_SHIFT 12
+#define RTC_HOUR_MASK (0x1F << RTC_HOUR_SHIFT) /* Hour [0-23] */
+#define RTC_WDAY_SHIFT 17
+#define RTC_WDAY_MASK (0x7 << RTC_WDAY_SHIFT) /* Day of Week [1-7] 1=Sunday */
+#define RTC_MDAY_SHIFT 20
+#define RTC_MDAY_MASK (0x1F << RTC_MDAY_SHIFT) /* Day of Month [1-31] */
+#define RTC_MON_SHIFT 25
+#define RTC_MON_MASK (0xF << RTC_MON_SHIFT) /* Month [1-12] 1=January */
+
+#define RTC_TIMER_FREQ 32768
 
 struct pl031_local {
        struct rtc_device *rtc;
        void __iomem *base;
+       u8 hw_designer;
+       u8 hw_revision:4;
 };
 
-static irqreturn_t pl031_interrupt(int irq, void *dev_id)
+static int pl031_alarm_irq_enable(struct device *dev,
+       unsigned int enabled)
+{
+       struct pl031_local *ldata = dev_get_drvdata(dev);
+       unsigned long imsc;
+
+       /* Clear any pending alarm interrupts. */
+       writel(RTC_BIT_AI, ldata->base + RTC_ICR);
+
+       imsc = readl(ldata->base + RTC_IMSC);
+
+       if (enabled == 1)
+               writel(imsc | RTC_BIT_AI, ldata->base + RTC_IMSC);
+       else
+               writel(imsc & ~RTC_BIT_AI, ldata->base + RTC_IMSC);
+
+       return 0;
+}
+
+/*
+ * Convert Gregorian date to ST v2 RTC format.
+ */
+static int pl031_stv2_tm_to_time(struct device *dev,
+                                struct rtc_time *tm, unsigned long *st_time,
+       unsigned long *bcd_year)
+{
+       int year = tm->tm_year + 1900;
+       int wday = tm->tm_wday;
+
+       /* wday masking is not working in hardware so wday must be valid */
+       if (wday < -1 || wday > 6) {
+               dev_err(dev, "invalid wday value %d\n", tm->tm_wday);
+               return -EINVAL;
+       } else if (wday == -1) {
+               /* wday is not provided, calculate it here */
+               unsigned long time;
+               struct rtc_time calc_tm;
+
+               rtc_tm_to_time(tm, &time);
+               rtc_time_to_tm(time, &calc_tm);
+               wday = calc_tm.tm_wday;
+       }
+
+       *bcd_year = (bin2bcd(year % 100) | bin2bcd(year / 100) << 8);
+
+       *st_time = ((tm->tm_mon + 1) << RTC_MON_SHIFT)
+                       |       (tm->tm_mday << RTC_MDAY_SHIFT)
+                       |       ((wday + 1) << RTC_WDAY_SHIFT)
+                       |       (tm->tm_hour << RTC_HOUR_SHIFT)
+                       |       (tm->tm_min << RTC_MIN_SHIFT)
+                       |       (tm->tm_sec << RTC_SEC_SHIFT);
+
+       return 0;
+}
+
+/*
+ * Convert ST v2 RTC format to Gregorian date.
+ */
+static int pl031_stv2_time_to_tm(unsigned long st_time, unsigned long bcd_year,
+       struct rtc_time *tm)
+{
+       tm->tm_year = bcd2bin(bcd_year) + (bcd2bin(bcd_year >> 8) * 100);
+       tm->tm_mon  = ((st_time & RTC_MON_MASK) >> RTC_MON_SHIFT) - 1;
+       tm->tm_mday = ((st_time & RTC_MDAY_MASK) >> RTC_MDAY_SHIFT);
+       tm->tm_wday = ((st_time & RTC_WDAY_MASK) >> RTC_WDAY_SHIFT) - 1;
+       tm->tm_hour = ((st_time & RTC_HOUR_MASK) >> RTC_HOUR_SHIFT);
+       tm->tm_min  = ((st_time & RTC_MIN_MASK) >> RTC_MIN_SHIFT);
+       tm->tm_sec  = ((st_time & RTC_SEC_MASK) >> RTC_SEC_SHIFT);
+
+       tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
+       tm->tm_year -= 1900;
+
+       return 0;
+}
+
+static int pl031_stv2_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct pl031_local *ldata = dev_get_drvdata(dev);
+
+       pl031_stv2_time_to_tm(readl(ldata->base + RTC_DR),
+                       readl(ldata->base + RTC_YDR), tm);
+
+       return 0;
+}
+
+static int pl031_stv2_set_time(struct device *dev, struct rtc_time *tm)
+{
+       unsigned long time;
+       unsigned long bcd_year;
+       struct pl031_local *ldata = dev_get_drvdata(dev);
+       int ret;
+
+       ret = pl031_stv2_tm_to_time(dev, tm, &time, &bcd_year);
+       if (ret == 0) {
+               writel(bcd_year, ldata->base + RTC_YLR);
+               writel(time, ldata->base + RTC_LR);
+       }
+
+       return ret;
+}
+
+static int pl031_stv2_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 {
-       struct rtc_device *rtc = dev_id;
+       struct pl031_local *ldata = dev_get_drvdata(dev);
+       int ret;
 
-       rtc_update_irq(rtc, 1, RTC_AF);
+       ret = pl031_stv2_time_to_tm(readl(ldata->base + RTC_MR),
+                       readl(ldata->base + RTC_YMR), &alarm->time);
 
-       return IRQ_HANDLED;
+       alarm->pending = readl(ldata->base + RTC_RIS) & RTC_BIT_AI;
+       alarm->enabled = readl(ldata->base + RTC_IMSC) & RTC_BIT_AI;
+
+       return ret;
 }
 
-static int pl031_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+static int pl031_stv2_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 {
        struct pl031_local *ldata = dev_get_drvdata(dev);
+       unsigned long time;
+       unsigned long bcd_year;
+       int ret;
+
+       /* At the moment, we can only deal with non-wildcarded alarm times. */
+       ret = rtc_valid_tm(&alarm->time);
+       if (ret == 0) {
+               ret = pl031_stv2_tm_to_time(dev, &alarm->time,
+                                           &time, &bcd_year);
+               if (ret == 0) {
+                       writel(bcd_year, ldata->base + RTC_YMR);
+                       writel(time, ldata->base + RTC_MR);
+
+                       pl031_alarm_irq_enable(dev, alarm->enabled);
+               }
+       }
+
+       return ret;
+}
+
+static irqreturn_t pl031_interrupt(int irq, void *dev_id)
+{
+       struct pl031_local *ldata = dev_id;
+       unsigned long rtcmis;
+       unsigned long events = 0;
+
+       rtcmis = readl(ldata->base + RTC_MIS);
+       if (rtcmis) {
+               writel(rtcmis, ldata->base + RTC_ICR);
+
+               if (rtcmis & RTC_BIT_AI)
+                       events |= (RTC_AF | RTC_IRQF);
+
+               /* Timer interrupt is only available in ST variants */
+               if ((rtcmis & RTC_BIT_PI) &&
+                       (ldata->hw_designer == AMBA_VENDOR_ST))
+                       events |= (RTC_PF | RTC_IRQF);
+
+               rtc_update_irq(ldata->rtc, 1, events);
 
-       switch (cmd) {
-       case RTC_AIE_OFF:
-               writel(1, ldata->base + RTC_MIS);
-               return 0;
-       case RTC_AIE_ON:
-               writel(0, ldata->base + RTC_MIS);
-               return 0;
+               return IRQ_HANDLED;
        }
 
-       return -ENOIOCTLCMD;
+       return IRQ_NONE;
 }
 
 static int pl031_read_time(struct device *dev, struct rtc_time *tm)
@@ -74,11 +252,14 @@ static int pl031_set_time(struct device *dev, struct rtc_time *tm)
 {
        unsigned long time;
        struct pl031_local *ldata = dev_get_drvdata(dev);
+       int ret;
 
-       rtc_tm_to_time(tm, &time);
-       writel(time, ldata->base + RTC_LR);
+       ret = rtc_tm_to_time(tm, &time);
 
-       return 0;
+       if (ret == 0)
+               writel(time, ldata->base + RTC_LR);
+
+       return ret;
 }
 
 static int pl031_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
@@ -86,8 +267,9 @@ static int pl031_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
        struct pl031_local *ldata = dev_get_drvdata(dev);
 
        rtc_time_to_tm(readl(ldata->base + RTC_MR), &alarm->time);
-       alarm->pending = readl(ldata->base + RTC_RIS);
-       alarm->enabled = readl(ldata->base + RTC_IMSC);
+
+       alarm->pending = readl(ldata->base + RTC_RIS) & RTC_BIT_AI;
+       alarm->enabled = readl(ldata->base + RTC_IMSC) & RTC_BIT_AI;
 
        return 0;
 }
@@ -96,22 +278,71 @@ static int pl031_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 {
        struct pl031_local *ldata = dev_get_drvdata(dev);
        unsigned long time;
+       int ret;
+
+       /* At the moment, we can only deal with non-wildcarded alarm times. */
+       ret = rtc_valid_tm(&alarm->time);
+       if (ret == 0) {
+               ret = rtc_tm_to_time(&alarm->time, &time);
+               if (ret == 0) {
+                       writel(time, ldata->base + RTC_MR);
+                       pl031_alarm_irq_enable(dev, alarm->enabled);
+               }
+       }
+
+       return ret;
+}
+
+/* Periodic interrupt is only available in ST variants. */
+static int pl031_irq_set_state(struct device *dev, int enabled)
+{
+       struct pl031_local *ldata = dev_get_drvdata(dev);
+
+       if (enabled == 1) {
+               /* Clear any pending timer interrupt. */
+               writel(RTC_BIT_PI, ldata->base + RTC_ICR);
+
+               writel(readl(ldata->base + RTC_IMSC) | RTC_BIT_PI,
+                       ldata->base + RTC_IMSC);
 
-       rtc_tm_to_time(&alarm->time, &time);
+               /* Now start the timer */
+               writel(readl(ldata->base + RTC_TCR) | RTC_TCR_EN,
+                       ldata->base + RTC_TCR);
 
-       writel(time, ldata->base + RTC_MR);
-       writel(!alarm->enabled, ldata->base + RTC_MIS);
+       } else {
+               writel(readl(ldata->base + RTC_IMSC) & (~RTC_BIT_PI),
+                       ldata->base + RTC_IMSC);
+
+               /* Also stop the timer */
+               writel(readl(ldata->base + RTC_TCR) & (~RTC_TCR_EN),
+                       ldata->base + RTC_TCR);
+       }
+       /* Wait at least 1 RTC32 clock cycle to ensure next access
+        * to RTC_TCR will succeed.
+        */
+       udelay(40);
 
        return 0;
 }
 
-static const struct rtc_class_ops pl031_ops = {
-       .ioctl = pl031_ioctl,
-       .read_time = pl031_read_time,
-       .set_time = pl031_set_time,
-       .read_alarm = pl031_read_alarm,
-       .set_alarm = pl031_set_alarm,
-};
+static int pl031_irq_set_freq(struct device *dev, int freq)
+{
+       struct pl031_local *ldata = dev_get_drvdata(dev);
+
+       /* Cant set timer if it is already enabled */
+       if (readl(ldata->base + RTC_TCR) & RTC_TCR_EN) {
+               dev_err(dev, "can't change frequency while timer enabled\n");
+               return -EINVAL;
+       }
+
+       /* If self start bit in RTC_TCR is set timer will start here,
+        * but we never set that bit. Instead we start the timer when
+        * set_state is called with enabled == 1.
+        */
+       writel(RTC_TIMER_FREQ / freq, ldata->base + RTC_TLR);
+
+       return 0;
+}
 
 static int pl031_remove(struct amba_device *adev)
 {
@@ -131,18 +362,20 @@ static int pl031_probe(struct amba_device *adev, struct amba_id *id)
 {
        int ret;
        struct pl031_local *ldata;
+       struct rtc_class_ops *ops = id->data;
 
        ret = amba_request_regions(adev, NULL);
        if (ret)
                goto err_req;
 
-       ldata = kmalloc(sizeof(struct pl031_local), GFP_KERNEL);
+       ldata = kzalloc(sizeof(struct pl031_local), GFP_KERNEL);
        if (!ldata) {
                ret = -ENOMEM;
                goto out;
        }
 
        ldata->base = ioremap(adev->res.start, resource_size(&adev->res));
+
        if (!ldata->base) {
                ret = -ENOMEM;
                goto out_no_remap;
@@ -150,24 +383,36 @@ static int pl031_probe(struct amba_device *adev, struct amba_id *id)
 
        amba_set_drvdata(adev, ldata);
 
-       if (request_irq(adev->irq[0], pl031_interrupt, IRQF_DISABLED,
-                       "rtc-pl031", ldata->rtc)) {
-               ret = -EIO;
-               goto out_no_irq;
-       }
+       ldata->hw_designer = amba_manf(adev);
+       ldata->hw_revision = amba_rev(adev);
+
+       dev_dbg(&adev->dev, "designer ID = 0x%02x\n", ldata->hw_designer);
+       dev_dbg(&adev->dev, "revision = 0x%01x\n", ldata->hw_revision);
 
-       ldata->rtc = rtc_device_register("pl031", &adev->dev, &pl031_ops,
-                                        THIS_MODULE);
+       /* Enable the clockwatch on ST Variants */
+       if ((ldata->hw_designer == AMBA_VENDOR_ST) &&
+           (ldata->hw_revision > 1))
+               writel(readl(ldata->base + RTC_CR) | RTC_CR_CWEN,
+                      ldata->base + RTC_CR);
+
+       ldata->rtc = rtc_device_register("pl031", &adev->dev, ops,
+                                       THIS_MODULE);
        if (IS_ERR(ldata->rtc)) {
                ret = PTR_ERR(ldata->rtc);
                goto out_no_rtc;
        }
 
+       if (request_irq(adev->irq[0], pl031_interrupt,
+                       IRQF_DISABLED | IRQF_SHARED, "rtc-pl031", ldata)) {
+               ret = -EIO;
+               goto out_no_irq;
+       }
+
        return 0;
 
-out_no_rtc:
-       free_irq(adev->irq[0], ldata->rtc);
 out_no_irq:
+       rtc_device_unregister(ldata->rtc);
+out_no_rtc:
        iounmap(ldata->base);
        amba_set_drvdata(adev, NULL);
 out_no_remap:
@@ -175,13 +420,57 @@ out_no_remap:
 out:
        amba_release_regions(adev);
 err_req:
+
        return ret;
 }
 
+/* Operations for the original ARM version */
+static struct rtc_class_ops arm_pl031_ops = {
+       .read_time = pl031_read_time,
+       .set_time = pl031_set_time,
+       .read_alarm = pl031_read_alarm,
+       .set_alarm = pl031_set_alarm,
+       .alarm_irq_enable = pl031_alarm_irq_enable,
+};
+
+/* The First ST derivative */
+static struct rtc_class_ops stv1_pl031_ops = {
+       .read_time = pl031_read_time,
+       .set_time = pl031_set_time,
+       .read_alarm = pl031_read_alarm,
+       .set_alarm = pl031_set_alarm,
+       .alarm_irq_enable = pl031_alarm_irq_enable,
+       .irq_set_state = pl031_irq_set_state,
+       .irq_set_freq = pl031_irq_set_freq,
+};
+
+/* And the second ST derivative */
+static struct rtc_class_ops stv2_pl031_ops = {
+       .read_time = pl031_stv2_read_time,
+       .set_time = pl031_stv2_set_time,
+       .read_alarm = pl031_stv2_read_alarm,
+       .set_alarm = pl031_stv2_set_alarm,
+       .alarm_irq_enable = pl031_alarm_irq_enable,
+       .irq_set_state = pl031_irq_set_state,
+       .irq_set_freq = pl031_irq_set_freq,
+};
+
 static struct amba_id pl031_ids[] __initdata = {
        {
                .id = 0x00041031,
                .mask = 0x000fffff,
+               .data = &arm_pl031_ops,
+       },
+       /* ST Micro variants */
+       {
+               .id = 0x00180031,
+               .mask = 0x00ffffff,
+               .data = &stv1_pl031_ops,
+       },
+       {
+               .id = 0x00280031,
+               .mask = 0x00ffffff,
+               .data = &stv2_pl031_ops,
        },
        {0, 0},
 };
index 9ab1ae40565fffc7342638a23ef895ad46eeab8a..4951aa82e9f5c30fd676d3978900f09924588322 100644 (file)
@@ -2139,9 +2139,8 @@ static void dasd_setup_queue(struct dasd_block *block)
 
        blk_queue_logical_block_size(block->request_queue, block->bp_block);
        max = block->base->discipline->max_blocks << block->s2b_shift;
-       blk_queue_max_sectors(block->request_queue, max);
-       blk_queue_max_phys_segments(block->request_queue, -1L);
-       blk_queue_max_hw_segments(block->request_queue, -1L);
+       blk_queue_max_hw_sectors(block->request_queue, max);
+       blk_queue_max_segments(block->request_queue, -1L);
        /* with page sized segments we can translate each segement into
         * one idaw/tidaw
         */
index 8d3d720737da20879f1ac85b1f9da6a7432e99cd..097da8ce6be6631eb515105773e523be43f02fb5 100644 (file)
@@ -222,9 +222,8 @@ tapeblock_setup_device(struct tape_device * device)
                goto cleanup_queue;
 
        blk_queue_logical_block_size(blkdat->request_queue, TAPEBLOCK_HSEC_SIZE);
-       blk_queue_max_sectors(blkdat->request_queue, TAPEBLOCK_MAX_SEC);
-       blk_queue_max_phys_segments(blkdat->request_queue, -1L);
-       blk_queue_max_hw_segments(blkdat->request_queue, -1L);
+       blk_queue_max_hw_sectors(blkdat->request_queue, TAPEBLOCK_MAX_SEC);
+       blk_queue_max_segments(blkdat->request_queue, -1L);
        blk_queue_max_segment_size(blkdat->request_queue, -1L);
        blk_queue_segment_boundary(blkdat->request_queue, -1L);
 
index 87b536a97cb4b7abddb1c46f7ac734926d61f1dd..732f6d35b4a8e4aebf9af1c7ef07bb593edf9a3f 100644 (file)
@@ -4195,7 +4195,7 @@ static void ibmvfc_tgt_add_rport(struct ibmvfc_target *tgt)
                if (tgt->service_parms.class3_parms[0] & 0x80000000)
                        rport->supported_classes |= FC_COS_CLASS3;
                if (rport->rqst_q)
-                       blk_queue_max_hw_segments(rport->rqst_q, 1);
+                       blk_queue_max_segments(rport->rqst_q, 1);
        } else
                tgt_dbg(tgt, "rport add failed\n");
        spin_unlock_irqrestore(vhost->host->host_lock, flags);
@@ -4669,7 +4669,7 @@ static int ibmvfc_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        }
 
        if (shost_to_fc_host(shost)->rqst_q)
-               blk_queue_max_hw_segments(shost_to_fc_host(shost)->rqst_q, 1);
+               blk_queue_max_segments(shost_to_fc_host(shost)->rqst_q, 1);
        dev_set_drvdata(dev, vhost);
        spin_lock(&ibmvfc_driver_lock);
        list_add_tail(&vhost->queue, &ibmvfc_head);
index 9e52d16c7c3908319e97eff73d85de1102ac8859..032f0d0e6cb454695dffaec23b4ddfc0a9fa279f 100644 (file)
@@ -3674,7 +3674,7 @@ static int ipr_slave_configure(struct scsi_device *sdev)
                if (ipr_is_vset_device(res)) {
                        blk_queue_rq_timeout(sdev->request_queue,
                                             IPR_VSET_RW_TIMEOUT);
-                       blk_queue_max_sectors(sdev->request_queue, IPR_VSET_MAX_SECTORS);
+                       blk_queue_max_hw_sectors(sdev->request_queue, IPR_VSET_MAX_SECTORS);
                }
                if (ipr_is_vset_device(res) || ipr_is_scsi_disk(res))
                        sdev->allow_restart = 1;
index b6f1ef954af1b469a75ca7ab96c1112b8034146c..9b1c1433c26bd1b538833397bd8e38d5f619a6da 100644 (file)
@@ -235,7 +235,7 @@ static int pmcraid_slave_configure(struct scsi_device *scsi_dev)
                scsi_dev->allow_restart = 1;
                blk_queue_rq_timeout(scsi_dev->request_queue,
                                     PMCRAID_VSET_IO_TIMEOUT);
-               blk_queue_max_sectors(scsi_dev->request_queue,
+               blk_queue_max_hw_sectors(scsi_dev->request_queue,
                                      PMCRAID_VSET_MAX_SECTORS);
        }
 
index 513661f45e5f23e69c2e0d8c6f5deb963365dff7..1c08f6164658155d370735e35cfbdf6b22ae7713 100644 (file)
@@ -1018,6 +1018,8 @@ static int scsi_vpd_inquiry(struct scsi_device *sdev, unsigned char *buffer,
  * scsi_get_vpd_page - Get Vital Product Data from a SCSI device
  * @sdev: The device to ask
  * @page: Which Vital Product Data to return
+ * @buf: where to store the VPD
+ * @buf_len: number of bytes in the VPD buffer area
  *
  * SCSI devices may optionally supply Vital Product Data.  Each 'page'
  * of VPD is defined in the appropriate SCSI document (eg SPC, SBC).
index 56977097de9f84a5e10e560f787c51ad35861729..1646fe7cbd4b7fcef1b79c98f5ac70a27ddc31f7 100644 (file)
@@ -1630,10 +1630,10 @@ struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost,
        /*
         * this limit is imposed by hardware restrictions
         */
-       blk_queue_max_hw_segments(q, shost->sg_tablesize);
-       blk_queue_max_phys_segments(q, SCSI_MAX_SG_CHAIN_SEGMENTS);
+       blk_queue_max_segments(q, min_t(unsigned short, shost->sg_tablesize,
+                                       SCSI_MAX_SG_CHAIN_SEGMENTS));
 
-       blk_queue_max_sectors(q, shost->max_sectors);
+       blk_queue_max_hw_sectors(q, shost->max_sectors);
        blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost));
        blk_queue_segment_boundary(q, shost->dma_boundary);
        dma_set_seg_boundary(dev, shost->dma_boundary);
index f697229ae5a98a25b3620d114b1765a718c7c9fc..4bc8b77a2ef3ae55d71606310213f3007f2c1a56 100644 (file)
@@ -879,7 +879,7 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
         * broken RA4x00 Compaq Disk Array
         */
        if (*bflags & BLIST_MAX_512)
-               blk_queue_max_sectors(sdev->request_queue, 512);
+               blk_queue_max_hw_sectors(sdev->request_queue, 512);
 
        /*
         * Some devices may not want to have a start command automatically
index 040f751809ea97c4e09af568aa327e178e9f4218..c996d98636f340704b82c0fab8d445c1591823ff 100644 (file)
@@ -287,8 +287,7 @@ sg_open(struct inode *inode, struct file *filp)
        if (list_empty(&sdp->sfds)) {   /* no existing opens on this device */
                sdp->sgdebug = 0;
                q = sdp->device->request_queue;
-               sdp->sg_tablesize = min(queue_max_hw_segments(q),
-                                       queue_max_phys_segments(q));
+               sdp->sg_tablesize = queue_max_segments(q);
        }
        if ((sfp = sg_add_sfp(sdp, dev)))
                filp->private_data = sfp;
@@ -1376,8 +1375,7 @@ static Sg_device *sg_alloc(struct gendisk *disk, struct scsi_device *scsidp)
        sdp->device = scsidp;
        INIT_LIST_HEAD(&sdp->sfds);
        init_waitqueue_head(&sdp->o_excl_wait);
-       sdp->sg_tablesize = min(queue_max_hw_segments(q),
-                               queue_max_phys_segments(q));
+       sdp->sg_tablesize = queue_max_segments(q);
        sdp->index = k;
        kref_init(&sdp->d_ref);
 
index d04ea9a6f6732b27526d748ba5b2524e6ebb7c23..f67d1a159aad9173982bacce034b88f7d7cb6732 100644 (file)
@@ -3983,8 +3983,7 @@ static int st_probe(struct device *dev)
                return -ENODEV;
        }
 
-       i = min(queue_max_hw_segments(SDp->request_queue),
-               queue_max_phys_segments(SDp->request_queue));
+       i = queue_max_segments(SDp->request_queue);
        if (st_max_sg_segs < i)
                i = st_max_sg_segs;
        buffer = new_tape_buffer((SDp->host)->unchecked_isa_dma, i);
index ef7adc8135dd4755fbd3cbde2c560988ea2afc0f..ce6c35333ff7b9faaf65acfc087ace884f150c60 100644 (file)
@@ -71,6 +71,7 @@ struct uart_amba_port {
        unsigned int            im;     /* interrupt mask */
        unsigned int            old_status;
        unsigned int            ifls;   /* vendor-specific */
+       bool                    autorts;
 };
 
 /* There is by now at least one vendor with differing details, so handle it */
@@ -308,6 +309,11 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
        TIOCMBIT(TIOCM_OUT1, UART011_CR_OUT1);
        TIOCMBIT(TIOCM_OUT2, UART011_CR_OUT2);
        TIOCMBIT(TIOCM_LOOP, UART011_CR_LBE);
+
+       if (uap->autorts) {
+               /* We need to disable auto-RTS if we want to turn RTS off */
+               TIOCMBIT(TIOCM_RTS, UART011_CR_RTSEN);
+       }
 #undef TIOCMBIT
 
        writew(cr, uap->port.membase + UART011_CR);
@@ -437,6 +443,7 @@ static void pl011_shutdown(struct uart_port *port)
        /*
         * disable the port
         */
+       uap->autorts = false;
        writew(UART01x_CR_UARTEN | UART011_CR_TXE, uap->port.membase + UART011_CR);
 
        /*
@@ -456,6 +463,7 @@ static void
 pl011_set_termios(struct uart_port *port, struct ktermios *termios,
                     struct ktermios *old)
 {
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
        unsigned int lcr_h, old_cr;
        unsigned long flags;
        unsigned int baud, quot;
@@ -532,6 +540,17 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
        old_cr = readw(port->membase + UART011_CR);
        writew(0, port->membase + UART011_CR);
 
+       if (termios->c_cflag & CRTSCTS) {
+               if (old_cr & UART011_CR_RTS)
+                       old_cr |= UART011_CR_RTSEN;
+
+               old_cr |= UART011_CR_CTSEN;
+               uap->autorts = true;
+       } else {
+               old_cr &= ~(UART011_CR_CTSEN | UART011_CR_RTSEN);
+               uap->autorts = false;
+       }
+
        /* Set baud rate */
        writew(quot & 0x3f, port->membase + UART011_FBRD);
        writew(quot >> 6, port->membase + UART011_IBRD);
index ff5bbb9c43c9961485b94f8cb86e5fd349789823..9aeb6811310001619baa9ffffbc4d4de2274ffcc 100644 (file)
@@ -363,6 +363,7 @@ struct pl022 {
        void                            *rx_end;
        enum ssp_reading                read;
        enum ssp_writing                write;
+       u32                             exp_fifo_level;
 };
 
 /**
@@ -501,6 +502,9 @@ static int flush(struct pl022 *pl022)
                while (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RNE)
                        readw(SSP_DR(pl022->virtbase));
        } while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_BSY) && limit--);
+
+       pl022->exp_fifo_level = 0;
+
        return limit;
 }
 
@@ -583,10 +587,9 @@ static void readwriter(struct pl022 *pl022)
         * errons in 8bit wide transfers on ARM variants (just 8 words
         * FIFO, means only 8x8 = 64 bits in FIFO) at least.
         *
-        * FIXME: currently we have no logic to account for this.
-        * perhaps there is even something broken in HW regarding
-        * 8bit transfers (it doesn't fail on 16bit) so this needs
-        * more investigation...
+        * To prevent this issue, the TX FIFO is only filled to the
+        * unused RX FIFO fill length, regardless of what the TX
+        * FIFO status flag indicates.
         */
        dev_dbg(&pl022->adev->dev,
                "%s, rx: %p, rxend: %p, tx: %p, txend: %p\n",
@@ -613,11 +616,12 @@ static void readwriter(struct pl022 *pl022)
                        break;
                }
                pl022->rx += (pl022->cur_chip->n_bytes);
+               pl022->exp_fifo_level--;
        }
        /*
-        * Write as much as you can, while keeping an eye on the RX FIFO!
+        * Write as much as possible up to the RX FIFO size
         */
-       while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_TNF)
+       while ((pl022->exp_fifo_level < pl022->vendor->fifodepth)
               && (pl022->tx < pl022->tx_end)) {
                switch (pl022->write) {
                case WRITING_NULL:
@@ -634,6 +638,7 @@ static void readwriter(struct pl022 *pl022)
                        break;
                }
                pl022->tx += (pl022->cur_chip->n_bytes);
+               pl022->exp_fifo_level++;
                /*
                 * This inner reader takes care of things appearing in the RX
                 * FIFO as we're transmitting. This will happen a lot since the
@@ -660,6 +665,7 @@ static void readwriter(struct pl022 *pl022)
                                break;
                        }
                        pl022->rx += (pl022->cur_chip->n_bytes);
+                       pl022->exp_fifo_level--;
                }
        }
        /*
index 62b282844a53eb2e29ff96e418d95d778b1fc700..45d908114d11c27961ad04b713863805a9142dac 100644 (file)
@@ -363,10 +363,7 @@ static int blkvsc_probe(struct device *device)
        blkdev->gd->queue = blk_init_queue(blkvsc_request, &blkdev->lock);
 
        blk_queue_max_segment_size(blkdev->gd->queue, PAGE_SIZE);
-       blk_queue_max_phys_segments(blkdev->gd->queue,
-                                   MAX_MULTIPAGE_BUFFER_COUNT);
-       blk_queue_max_hw_segments(blkdev->gd->queue,
-                                 MAX_MULTIPAGE_BUFFER_COUNT);
+       blk_queue_max_segments(blkdev->gd->queue, MAX_MULTIPAGE_BUFFER_COUNT);
        blk_queue_segment_boundary(blkdev->gd->queue, PAGE_SIZE-1);
        blk_queue_bounce_limit(blkdev->gd->queue, BLK_BOUNCE_ANY);
        blk_queue_dma_alignment(blkdev->gd->queue, 511);
index 3817d7497049b5b12a647cfb9010af6961c532c5..fcba78d21636e795f8812e1869d2244ccc0b841f 100644 (file)
@@ -62,7 +62,7 @@ static int phison_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
        };
        const struct ata_port_info *ppi[] = { &info, NULL };
 
-       ret = ata_pci_sff_init_one(pdev, ppi, &phison_sht, NULL);
+       ret = ata_pci_sff_init_one(pdev, ppi, &phison_sht, NULL, 0);
 
        dev_dbg(&pdev->dev, "phison_init_one(), ret = %x\n", ret);
 
index df77f6131c739ca1b7242a7fa03ba400f3cfc042..f1e3aad76c3766fec509b898d7e50ac0fdb9ee23 100644 (file)
@@ -60,7 +60,7 @@ DECLARE_UAC_AC_HEADER_DESCRIPTOR(2);
 #define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH + UAC_DT_INPUT_TERMINAL_SIZE \
        + UAC_DT_OUTPUT_TERMINAL_SIZE + UAC_DT_FEATURE_UNIT_SIZE(0))
 /* B.3.2  Class-Specific AC Interface Descriptor */
-static struct uac_ac_header_descriptor_2 ac_header_desc = {
+static struct uac_ac_header_descriptor_v1_2 ac_header_desc = {
        .bLength =              UAC_DT_AC_HEADER_LENGTH,
        .bDescriptorType =      USB_DT_CS_INTERFACE,
        .bDescriptorSubtype =   UAC_HEADER,
@@ -124,7 +124,7 @@ static struct usb_audio_control_selector feature_unit = {
 };
 
 #define OUTPUT_TERMINAL_ID     3
-static struct uac_output_terminal_descriptor output_terminal_desc = {
+static struct uac_output_terminal_descriptor_v1 output_terminal_desc = {
        .bLength                = UAC_DT_OUTPUT_TERMINAL_SIZE,
        .bDescriptorType        = USB_DT_CS_INTERFACE,
        .bDescriptorSubtype     = UAC_OUTPUT_TERMINAL,
@@ -154,7 +154,7 @@ static struct usb_interface_descriptor as_interface_alt_1_desc = {
 };
 
 /* B.4.2  Class-Specific AS Interface Descriptor */
-static struct uac_as_header_descriptor as_header_desc = {
+static struct uac_as_header_descriptor_v1 as_header_desc = {
        .bLength =              UAC_DT_AS_HEADER_SIZE,
        .bDescriptorType =      USB_DT_CS_INTERFACE,
        .bDescriptorSubtype =   UAC_AS_GENERAL,
index d0b1e836f0e051582880e5f04a27829967508389..5f6a2e0a9357bd680182d96b74211ccd8c7f0354 100644 (file)
@@ -237,7 +237,7 @@ static const struct usb_interface_descriptor ac_interface_desc = {
 };
 
 /* B.3.2  Class-Specific AC Interface Descriptor */
-static const struct uac_ac_header_descriptor_1 ac_header_desc = {
+static const struct uac_ac_header_descriptor_v1_1 ac_header_desc = {
        .bLength =              UAC_DT_AC_HEADER_SIZE(1),
        .bDescriptorType =      USB_DT_CS_INTERFACE,
        .bDescriptorSubtype =   USB_MS_HEADER,
index e5e6df39e73707989711ea0284a4109d56409b44..aadc16b5eed79c8d6ee0801c948c3172f1e4a6e9 100644 (file)
@@ -134,14 +134,14 @@ static int slave_configure(struct scsi_device *sdev)
                if (us->fflags & US_FL_MAX_SECTORS_MIN)
                        max_sectors = PAGE_CACHE_SIZE >> 9;
                if (queue_max_sectors(sdev->request_queue) > max_sectors)
-                       blk_queue_max_sectors(sdev->request_queue,
+                       blk_queue_max_hw_sectors(sdev->request_queue,
                                              max_sectors);
        } else if (sdev->type == TYPE_TAPE) {
                /* Tapes need much higher max_sector limits, so just
                 * raise it to the maximum possible (4 GB / 512) and
                 * let the queue segment size sort out the real limit.
                 */
-               blk_queue_max_sectors(sdev->request_queue, 0x7FFFFF);
+               blk_queue_max_hw_sectors(sdev->request_queue, 0x7FFFFF);
        }
 
        /* Some USB host controllers can't do DMA; they have to use PIO.
@@ -495,7 +495,7 @@ static ssize_t store_max_sectors(struct device *dev, struct device_attribute *at
        unsigned short ms;
 
        if (sscanf(buf, "%hu", &ms) > 0 && ms <= SCSI_DEFAULT_MAX_SECTORS) {
-               blk_queue_max_sectors(sdev->request_queue, ms);
+               blk_queue_max_hw_sectors(sdev->request_queue, ms);
                return strlen(buf);
        }
        return -EINVAL; 
index 1d5191fab62e440928376f33666a92a15d7be5df..1b65732169984032da0093371c448cfcf14db020 100644 (file)
@@ -473,7 +473,8 @@ static void vp_del_vqs(struct virtio_device *vdev)
 
        list_for_each_entry_safe(vq, n, &vdev->vqs, list) {
                info = vq->priv;
-               if (vp_dev->per_vq_vectors)
+               if (vp_dev->per_vq_vectors &&
+                       info->msix_vector != VIRTIO_MSI_NO_VECTOR)
                        free_irq(vp_dev->msix_entries[info->msix_vector].vector,
                                 vq);
                vp_del_vq(vq);
index 430a5848a9a5d40a6bb1aeb770c76e26df357be2..c7a9479934af87558e45bf16a036803060ede2f2 100644 (file)
@@ -96,9 +96,6 @@ static void wdt_enable(void)
 {
        spin_lock(&io_lock);
 
-       if (wdt_clk)
-               clk_set_rate(wdt_clk, 1);
-
        /* stop counter, initiate counter reset */
        __raw_writel(RESET_COUNT, WDTIM_CTRL(wdt_base));
        /*wait for reset to complete. 100% guarantee event */
@@ -125,19 +122,25 @@ static void wdt_disable(void)
        spin_lock(&io_lock);
 
        __raw_writel(0, WDTIM_CTRL(wdt_base));  /*stop counter */
-       if (wdt_clk)
-               clk_set_rate(wdt_clk, 0);
 
        spin_unlock(&io_lock);
 }
 
 static int pnx4008_wdt_open(struct inode *inode, struct file *file)
 {
+       int ret;
+
        if (test_and_set_bit(WDT_IN_USE, &wdt_status))
                return -EBUSY;
 
        clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
 
+       ret = clk_enable(wdt_clk);
+       if (ret) {
+               clear_bit(WDT_IN_USE, &wdt_status);
+               return ret;
+       }
+
        wdt_enable();
 
        return nonseekable_open(inode, file);
@@ -225,6 +228,7 @@ static int pnx4008_wdt_release(struct inode *inode, struct file *file)
                printk(KERN_WARNING "WATCHDOG: Device closed unexpectdly\n");
 
        wdt_disable();
+       clk_disable(wdt_clk);
        clear_bit(WDT_IN_USE, &wdt_status);
        clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
 
@@ -273,25 +277,33 @@ static int __devinit pnx4008_wdt_probe(struct platform_device *pdev)
        }
        wdt_base = (void __iomem *)IO_ADDRESS(res->start);
 
-       wdt_clk = clk_get(&pdev->dev, "wdt_ck");
+       wdt_clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(wdt_clk)) {
                ret = PTR_ERR(wdt_clk);
                release_resource(wdt_mem);
                kfree(wdt_mem);
                goto out;
-       } else
-               clk_set_rate(wdt_clk, 1);
+       }
+
+       ret = clk_enable(wdt_clk);
+       if (ret) {
+               release_resource(wdt_mem);
+               kfree(wdt_mem);
+               goto out;
+       }
 
        ret = misc_register(&pnx4008_wdt_miscdev);
        if (ret < 0) {
                printk(KERN_ERR MODULE_NAME "cannot register misc device\n");
                release_resource(wdt_mem);
                kfree(wdt_mem);
-               clk_set_rate(wdt_clk, 0);
+               clk_disable(wdt_clk);
+               clk_put(wdt_clk);
        } else {
                boot_status = (__raw_readl(WDTIM_RES(wdt_base)) & WDOG_RESET) ?
                    WDIOF_CARDRESET : 0;
                wdt_disable();          /*disable for now */
+               clk_disable(wdt_clk);
                set_bit(WDT_DEVICE_INITED, &wdt_status);
        }
 
@@ -302,11 +314,10 @@ out:
 static int __devexit pnx4008_wdt_remove(struct platform_device *pdev)
 {
        misc_deregister(&pnx4008_wdt_miscdev);
-       if (wdt_clk) {
-               clk_set_rate(wdt_clk, 0);
-               clk_put(wdt_clk);
-               wdt_clk = NULL;
-       }
+
+       clk_disable(wdt_clk);
+       clk_put(wdt_clk);
+
        if (wdt_mem) {
                release_resource(wdt_mem);
                kfree(wdt_mem);
index 88094afc29ea38c13906d861ca9bb7dd67c463a2..0bda289f86fc265e49faf5d646eee47c4b9b1f07 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -507,10 +507,8 @@ int bio_get_nr_vecs(struct block_device *bdev)
        int nr_pages;
 
        nr_pages = ((queue_max_sectors(q) << 9) + PAGE_SIZE - 1) >> PAGE_SHIFT;
-       if (nr_pages > queue_max_phys_segments(q))
-               nr_pages = queue_max_phys_segments(q);
-       if (nr_pages > queue_max_hw_segments(q))
-               nr_pages = queue_max_hw_segments(q);
+       if (nr_pages > queue_max_segments(q))
+               nr_pages = queue_max_segments(q);
 
        return nr_pages;
 }
@@ -557,7 +555,7 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page
                                        .bi_rw = bio->bi_rw,
                                };
 
-                               if (q->merge_bvec_fn(q, &bvm, prev) len) {
+                               if (q->merge_bvec_fn(q, &bvm, prev) != prev->bv_len) {
                                        prev->bv_len -= len;
                                        return 0;
                                }
@@ -575,8 +573,7 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page
         * make this too complex.
         */
 
-       while (bio->bi_phys_segments >= queue_max_phys_segments(q)
-              || bio->bi_phys_segments >= queue_max_hw_segments(q)) {
+       while (bio->bi_phys_segments >= queue_max_segments(q)) {
 
                if (retried_segments)
                        return 0;
@@ -611,7 +608,7 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page
                 * merge_bvec_fn() returns number of bytes it can accept
                 * at this offset
                 */
-               if (q->merge_bvec_fn(q, &bvm, bvec) len) {
+               if (q->merge_bvec_fn(q, &bvm, bvec) != bvec->bv_len) {
                        bvec->bv_page = NULL;
                        bvec->bv_len = 0;
                        bvec->bv_offset = 0;
index 64bc8998ac9aa22f5604ed7ccccc644e0b4fb563..e8865c11777f726a9622f7f7835a6c0ac8551021 100644 (file)
@@ -412,9 +412,10 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno,
        pdev = part_to_dev(p);
 
        p->start_sect = start;
-       p->alignment_offset = queue_sector_alignment_offset(disk->queue, start);
-       p->discard_alignment = queue_sector_discard_alignment(disk->queue,
-                                                             start);
+       p->alignment_offset =
+               queue_limit_alignment_offset(&disk->queue->limits, start);
+       p->discard_alignment =
+               queue_limit_discard_alignment(&disk->queue->limits, start);
        p->nr_sects = len;
        p->partno = partno;
        p->policy = get_disk_ro(disk);
index 473d584b1d315cf962d42a92c68cf7ebbd74d8ee..5b2e5e80ecb07bb211ec3e13a607ef37dbd8323c 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c1343a9265fad6291b28ba34a5c4bb897a25b56e..9cf736ea4691b6c0ac206789f30f73f3ab6dd3ac 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d814da4b5365dbcd0ccb5cc978b775c8ad27ab6c..d7726685797e76649bcaf5a9aa03010f33b99e4c 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 472b7bf0c5d4ebe9161d7f4d099169fe615f00b8..a091cabca4b1266f1c3cbdaac7d44f2a4c81be4c 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 54508ccea023f563c840639915c22c981e7cfe76..7bf83ddf82e03278c27d54cc9f20dd5360fbe31d 100644 (file)
@@ -252,8 +252,8 @@ struct acpi_device_wakeup_state {
 
 struct acpi_device_wakeup {
        acpi_handle gpe_device;
-       acpi_integer gpe_number;
-       acpi_integer sleep_state;
+       u64 gpe_number;
+       u64 sleep_state;
        struct acpi_handle_list resources;
        struct acpi_device_wakeup_state state;
        struct acpi_device_wakeup_flags flags;
@@ -383,7 +383,7 @@ struct acpi_pci_root {
 };
 
 /* helper */
-acpi_handle acpi_get_child(acpi_handle, acpi_integer);
+acpi_handle acpi_get_child(acpi_handle, u64);
 int acpi_is_root_bridge(acpi_handle);
 acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int);
 struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle);
index eb0e7189075f374d7f4370fb40d9fcf28e0c6510..b396854b83b06c9ec60b7b34a444eb75f95c0c9c 100644 (file)
@@ -8,7 +8,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -196,7 +196,7 @@ acpi_os_hotplug_execute(acpi_osd_exec_callback function, void *context);
 
 void acpi_os_wait_events_complete(void *context);
 
-void acpi_os_sleep(acpi_integer milliseconds);
+void acpi_os_sleep(u64 milliseconds);
 
 void acpi_os_stall(u32 microseconds);
 
@@ -227,7 +227,7 @@ acpi_os_read_pci_configuration(struct acpi_pci_id *pci_id,
 
 acpi_status
 acpi_os_write_pci_configuration(struct acpi_pci_id *pci_id,
-                               u32 reg, acpi_integer value, u32 width);
+                               u32 reg, u64 value, u32 width);
 
 /*
  * Interim function needed for PCI IRQ routing
index 3988f93b9c66fcdfe542d57e4e3da08624458a29..4447a0461bae44050c73e8d017cb63e06455d266 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -47,7 +47,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20091214
+#define ACPI_CA_VERSION                 0x20100121
 
 #include "actypes.h"
 #include "actbl.h"
index 9ffe00feada62ef7b91aa357849182bc7b66060a..e5526354ba5eab0142eb58159fa862e18d11cd13 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -397,7 +397,7 @@ struct acpi_resource {
 struct acpi_pci_routing_table {
        u32 length;
        u32 pin;
-       acpi_integer address;   /* here for 64-bit alignment */
+       u64 address;            /* here for 64-bit alignment */
        u32 source_index;
        char source[4];         /* pad to 64 bits so sizeof() works in all cases */
 };
index 1b658795260447b775eea26d2ac81e4730dfe16f..ad2001683ba7385d50c875eda327c4ac41894c48 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 0b9b430b092bea5e5b96fe478905e57bb890a48c..c637b75b9f3f542a61cfd2d6b3ddef1485691e5b 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 6f3dce9991e1ec18a75d0cafe74e272c8d12992a..5b02e307bff388a8c4b07f85d44f60a2ca4174bf 100644 (file)
@@ -1,3 +1,46 @@
+/******************************************************************************
+ *
+ * Name: actbl2.h - ACPI Specification Revision 2.0 Tables
+ *
+ *****************************************************************************/
+
+/*
+ * 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.
+ */
+
 #ifndef __ACTBL2_H__
 #define __ACTBL2_H__
 
index 73af408633719733fe1c405b0cc895df3bb2e819..3f08e64962f872838ccc14ee635426fe9517f46d 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -385,19 +385,6 @@ union uint64_overlay {
        struct uint64_struct part;
 };
 
-struct uint32_struct {
-       u32 lo;
-       u32 hi;
-};
-
-/*
- * Acpi integer width. In ACPI version 1, integers are 32 bits. In ACPI
- * version 2, integers are 64 bits. Note that this pertains to the ACPI integer
- * type only, not other integers used in the implementation of the ACPI CA
- * subsystem.
- */
-typedef unsigned long long acpi_integer;
-#define ACPI_INTEGER_MAX                ACPI_UINT64_MAX
 #define ACPI_INTEGER_BIT_SIZE           64
 #define ACPI_MAX_DECIMAL_DIGITS         20     /* 2^64 = 18,446,744,073,709,551,616 */
 
@@ -421,6 +408,19 @@ typedef unsigned long long acpi_integer;
 #define ACPI_WAIT_FOREVER               0xFFFF /* u16, as per ACPI spec */
 #define ACPI_DO_NOT_WAIT                0
 
+/*
+ * Obsolete: Acpi integer width. In ACPI version 1 (1996), integers are 32 bits.
+ * In ACPI version 2 (2000) and later, integers are 64 bits. Note that this
+ * pertains to the ACPI integer type only, not to other integers used in the
+ * implementation of the ACPICA subsystem.
+ *
+ * 01/2010: This type is obsolete and has been removed from the entire ACPICA
+ * code base. It remains here for compatibility with device drivers that use
+ * the type. However, it will be removed in the future.
+ */
+typedef u64 acpi_integer;
+#define ACPI_INTEGER_MAX                ACPI_UINT64_MAX
+
 /*******************************************************************************
  *
  * Commonly used macros
@@ -793,7 +793,7 @@ union acpi_object {
        acpi_object_type type;  /* See definition of acpi_ns_type for values */
        struct {
                acpi_object_type type;  /* ACPI_TYPE_INTEGER */
-               acpi_integer value;     /* The actual number */
+               u64 value;      /* The actual number */
        } integer;
 
        struct {
@@ -937,7 +937,7 @@ typedef
 acpi_status(*acpi_adr_space_handler) (u32 function,
                                      acpi_physical_address address,
                                      u32 bit_width,
-                                     acpi_integer * value,
+                                     u64 *value,
                                      void *handler_context,
                                      void *region_context);
 
@@ -997,7 +997,7 @@ struct acpi_device_info {
        u8 highest_dstates[4];  /* _sx_d values: 0xFF indicates not valid */
        u8 lowest_dstates[5];   /* _sx_w values: 0xFF indicates not valid */
        u32 current_status;     /* _STA value */
-       acpi_integer address;   /* _ADR value */
+       u64 address;    /* _ADR value */
        struct acpica_device_id hardware_id;    /* _HID value */
        struct acpica_device_id unique_id;      /* _UID value */
        struct acpica_device_id_list compatible_id_list;        /* _CID list <must be last> */
index e62f10d9a7d844e680a265d1f45b547fb00bacfc..c05aeba9e8f0e42a3441a66c75b02b0a973a046d 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -311,8 +311,8 @@ typedef char *va_list;
 #define ACPI_MEMCMP(s1,s2,n)    acpi_ut_memcmp((const char *)(s1), (const char *)(s2), (acpi_size)(n))
 #define ACPI_MEMCPY(d,s,n)      (void) acpi_ut_memcpy ((d), (s), (acpi_size)(n))
 #define ACPI_MEMSET(d,v,n)      (void) acpi_ut_memset ((d), (v), (acpi_size)(n))
-#define ACPI_TOUPPER            acpi_ut_to_upper
-#define ACPI_TOLOWER            acpi_ut_to_lower
+#define ACPI_TOUPPER(c)         acpi_ut_to_upper ((int) (c))
+#define ACPI_TOLOWER(c)         acpi_ut_to_lower ((int) (c))
 
 #endif                         /* ACPI_USE_SYSTEM_CLIBRARY */
 
index 6aadbf84ae71c014acf2d1a091756a0a83bd8e73..0cd53e3cd1a37789bb54edf99ec843df82c3b025 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 09469971472fb5587207d5f1517342e479c5abb2..e5039a2856f852b4a17d0729dd652422ed47c428 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2009, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 0ea5ef4eb6a94aaaa593003d0138ce1381f13e89..29831768c0e6ef3ac76b564b5bcf82b8f842c7d5 100644 (file)
@@ -92,11 +92,11 @@ struct acpi_processor_power {
 /* Performance Management */
 
 struct acpi_psd_package {
-       acpi_integer num_entries;
-       acpi_integer revision;
-       acpi_integer domain;
-       acpi_integer coord_type;
-       acpi_integer num_processors;
+       u64 num_entries;
+       u64 revision;
+       u64 domain;
+       u64 coord_type;
+       u64 num_processors;
 } __attribute__ ((packed));
 
 struct acpi_pct_register {
@@ -110,12 +110,12 @@ struct acpi_pct_register {
 } __attribute__ ((packed));
 
 struct acpi_processor_px {
-       acpi_integer core_frequency;    /* megahertz */
-       acpi_integer power;     /* milliWatts */
-       acpi_integer transition_latency;        /* microseconds */
-       acpi_integer bus_master_latency;        /* microseconds */
-       acpi_integer control;   /* control value */
-       acpi_integer status;    /* success indicator */
+       u64 core_frequency;     /* megahertz */
+       u64 power;      /* milliWatts */
+       u64 transition_latency; /* microseconds */
+       u64 bus_master_latency; /* microseconds */
+       u64 control;    /* control value */
+       u64 status;     /* success indicator */
 };
 
 struct acpi_processor_performance {
@@ -133,11 +133,11 @@ struct acpi_processor_performance {
 /* Throttling Control */
 
 struct acpi_tsd_package {
-       acpi_integer num_entries;
-       acpi_integer revision;
-       acpi_integer domain;
-       acpi_integer coord_type;
-       acpi_integer num_processors;
+       u64 num_entries;
+       u64 revision;
+       u64 domain;
+       u64 coord_type;
+       u64 num_processors;
 } __attribute__ ((packed));
 
 struct acpi_ptc_register {
@@ -151,11 +151,11 @@ struct acpi_ptc_register {
 } __attribute__ ((packed));
 
 struct acpi_processor_tx_tss {
-       acpi_integer freqpercentage;    /* */
-       acpi_integer power;     /* milliWatts */
-       acpi_integer transition_latency;        /* microseconds */
-       acpi_integer control;   /* control value */
-       acpi_integer status;    /* success indicator */
+       u64 freqpercentage;     /* */
+       u64 power;      /* milliWatts */
+       u64 transition_latency; /* microseconds */
+       u64 control;    /* control value */
+       u64 status;     /* success indicator */
 };
 struct acpi_processor_tx {
        u16 power;
index d93080748a91877cb71a6450f5318cb8dcdbf6a8..5b0d997f23efc802bad818d0a9b673c63b55c3ec 100644 (file)
@@ -43,6 +43,7 @@ header-y += blkpg.h
 header-y += bpqether.h
 header-y += bsg.h
 header-y += can.h
+header-y += cciss_defs.h
 header-y += cdk.h
 header-y += chio.h
 header-y += coda_psdev.h
index 20f31567ccee324d4218dc65527412c4bf032c9a..b4c85e2adef5e494d76a1c9a670ad22111e5c85b 100644 (file)
@@ -841,7 +841,8 @@ static inline int ata_id_current_chs_valid(const u16 *id)
 
 static inline int ata_id_is_cfa(const u16 *id)
 {
-       if (id[ATA_ID_CONFIG] == 0x848A)        /* Traditional CF */
+       if ((id[ATA_ID_CONFIG] == 0x848A) ||    /* Traditional CF */
+           (id[ATA_ID_CONFIG] == 0x844A))      /* Delkin Devices CF */
                return 1;
        /*
         * CF specs don't require specific value in the word 0 anymore and yet
index 1896e868854f949ed12c1ef38eb145b7c3633801..ebd22dbed861da16481a1f4995dd9460f71caca4 100644 (file)
@@ -316,8 +316,7 @@ struct queue_limits {
        unsigned int            discard_alignment;
 
        unsigned short          logical_block_size;
-       unsigned short          max_hw_segments;
-       unsigned short          max_phys_segments;
+       unsigned short          max_segments;
 
        unsigned char           misaligned;
        unsigned char           discard_misaligned;
@@ -462,6 +461,7 @@ struct request_queue
 #define QUEUE_FLAG_VIRT        QUEUE_FLAG_NONROT /* paravirt device */
 #define QUEUE_FLAG_IO_STAT     15      /* do IO stats */
 #define QUEUE_FLAG_DISCARD     16      /* supports DISCARD */
+#define QUEUE_FLAG_NOXMERGES   17      /* No extended merges */
 
 #define QUEUE_FLAG_DEFAULT     ((1 << QUEUE_FLAG_IO_STAT) |            \
                                 (1 << QUEUE_FLAG_CLUSTER) |            \
@@ -587,6 +587,8 @@ enum {
 #define blk_queue_tagged(q)    test_bit(QUEUE_FLAG_QUEUED, &(q)->queue_flags)
 #define blk_queue_stopped(q)   test_bit(QUEUE_FLAG_STOPPED, &(q)->queue_flags)
 #define blk_queue_nomerges(q)  test_bit(QUEUE_FLAG_NOMERGES, &(q)->queue_flags)
+#define blk_queue_noxmerges(q) \
+       test_bit(QUEUE_FLAG_NOXMERGES, &(q)->queue_flags)
 #define blk_queue_nonrot(q)    test_bit(QUEUE_FLAG_NONROT, &(q)->queue_flags)
 #define blk_queue_io_stat(q)   test_bit(QUEUE_FLAG_IO_STAT, &(q)->queue_flags)
 #define blk_queue_flushing(q)  ((q)->ordseq)
@@ -918,10 +920,27 @@ extern struct request_queue *blk_init_queue(request_fn_proc *, spinlock_t *);
 extern void blk_cleanup_queue(struct request_queue *);
 extern void blk_queue_make_request(struct request_queue *, make_request_fn *);
 extern void blk_queue_bounce_limit(struct request_queue *, u64);
-extern void blk_queue_max_sectors(struct request_queue *, unsigned int);
 extern void blk_queue_max_hw_sectors(struct request_queue *, unsigned int);
-extern void blk_queue_max_phys_segments(struct request_queue *, unsigned short);
-extern void blk_queue_max_hw_segments(struct request_queue *, unsigned short);
+
+/* Temporary compatibility wrapper */
+static inline void blk_queue_max_sectors(struct request_queue *q, unsigned int max)
+{
+       blk_queue_max_hw_sectors(q, max);
+}
+
+extern void blk_queue_max_segments(struct request_queue *, unsigned short);
+
+static inline void blk_queue_max_phys_segments(struct request_queue *q, unsigned short max)
+{
+       blk_queue_max_segments(q, max);
+}
+
+static inline void blk_queue_max_hw_segments(struct request_queue *q, unsigned short max)
+{
+       blk_queue_max_segments(q, max);
+}
+
+
 extern void blk_queue_max_segment_size(struct request_queue *, unsigned int);
 extern void blk_queue_max_discard_sectors(struct request_queue *q,
                unsigned int max_discard_sectors);
@@ -1014,11 +1033,15 @@ extern int blk_verify_command(unsigned char *cmd, fmode_t has_write_perm);
 #define MAX_PHYS_SEGMENTS 128
 #define MAX_HW_SEGMENTS 128
 #define SAFE_MAX_SECTORS 255
-#define BLK_DEF_MAX_SECTORS 1024
-
 #define MAX_SEGMENT_SIZE       65536
 
-#define BLK_SEG_BOUNDARY_MASK  0xFFFFFFFFUL
+enum blk_default_limits {
+       BLK_MAX_SEGMENTS        = 128,
+       BLK_SAFE_MAX_SECTORS    = 255,
+       BLK_DEF_MAX_SECTORS     = 1024,
+       BLK_MAX_SEGMENT_SIZE    = 65536,
+       BLK_SEG_BOUNDARY_MASK   = 0xFFFFFFFFUL,
+};
 
 #define blkdev_entry_to_request(entry) list_entry((entry), struct request, queuelist)
 
@@ -1042,14 +1065,9 @@ static inline unsigned int queue_max_hw_sectors(struct request_queue *q)
        return q->limits.max_hw_sectors;
 }
 
-static inline unsigned short queue_max_hw_segments(struct request_queue *q)
-{
-       return q->limits.max_hw_segments;
-}
-
-static inline unsigned short queue_max_phys_segments(struct request_queue *q)
+static inline unsigned short queue_max_segments(struct request_queue *q)
 {
-       return q->limits.max_phys_segments;
+       return q->limits.max_segments;
 }
 
 static inline unsigned int queue_max_segment_size(struct request_queue *q)
@@ -1110,18 +1128,13 @@ static inline int queue_alignment_offset(struct request_queue *q)
        return q->limits.alignment_offset;
 }
 
-static inline int queue_limit_alignment_offset(struct queue_limits *lim, sector_t offset)
+static inline int queue_limit_alignment_offset(struct queue_limits *lim, sector_t sector)
 {
        unsigned int granularity = max(lim->physical_block_size, lim->io_min);
+       unsigned int alignment = (sector << 9) & (granularity - 1);
 
-       offset &= granularity - 1;
-       return (granularity + lim->alignment_offset - offset) & (granularity - 1);
-}
-
-static inline int queue_sector_alignment_offset(struct request_queue *q,
-                                               sector_t sector)
-{
-       return queue_limit_alignment_offset(&q->limits, sector << 9);
+       return (granularity + lim->alignment_offset - alignment)
+               & (granularity - 1);
 }
 
 static inline int bdev_alignment_offset(struct block_device *bdev)
@@ -1145,10 +1158,8 @@ static inline int queue_discard_alignment(struct request_queue *q)
        return q->limits.discard_alignment;
 }
 
-static inline int queue_sector_discard_alignment(struct request_queue *q,
-                                                sector_t sector)
+static inline int queue_limit_discard_alignment(struct queue_limits *lim, sector_t sector)
 {
-       struct queue_limits *lim = &q->limits;
        unsigned int alignment = (sector << 9) & (lim->discard_granularity - 1);
 
        return (lim->discard_granularity + lim->discard_alignment - alignment)
diff --git a/include/linux/cciss_defs.h b/include/linux/cciss_defs.h
new file mode 100644 (file)
index 0000000..316b670
--- /dev/null
@@ -0,0 +1,130 @@
+#ifndef CCISS_DEFS_H
+#define CCISS_DEFS_H
+
+#include <linux/types.h>
+
+/* general boundary definitions */
+#define SENSEINFOBYTES          32 /* note that this value may vary
+                                     between host implementations */
+
+/* Command Status value */
+#define CMD_SUCCESS             0x0000
+#define CMD_TARGET_STATUS       0x0001
+#define CMD_DATA_UNDERRUN       0x0002
+#define CMD_DATA_OVERRUN        0x0003
+#define CMD_INVALID             0x0004
+#define CMD_PROTOCOL_ERR        0x0005
+#define CMD_HARDWARE_ERR        0x0006
+#define CMD_CONNECTION_LOST     0x0007
+#define CMD_ABORTED             0x0008
+#define CMD_ABORT_FAILED        0x0009
+#define CMD_UNSOLICITED_ABORT   0x000A
+#define CMD_TIMEOUT             0x000B
+#define CMD_UNABORTABLE                0x000C
+
+/* transfer direction */
+#define XFER_NONE               0x00
+#define XFER_WRITE              0x01
+#define XFER_READ               0x02
+#define XFER_RSVD               0x03
+
+/* task attribute */
+#define ATTR_UNTAGGED           0x00
+#define ATTR_SIMPLE             0x04
+#define ATTR_HEADOFQUEUE        0x05
+#define ATTR_ORDERED            0x06
+#define ATTR_ACA                0x07
+
+/* cdb type */
+#define TYPE_CMD                               0x00
+#define TYPE_MSG                               0x01
+
+/* Type defs used in the following structs */
+#define BYTE __u8
+#define WORD __u16
+#define HWORD __u16
+#define DWORD __u32
+
+#define CISS_MAX_LUN   1024
+
+#define LEVEL2LUN   1 /* index into Target(x) structure, due to byte swapping */
+#define LEVEL3LUN   0
+
+#pragma pack(1)
+
+/* Command List Structure */
+typedef union _SCSI3Addr_struct {
+   struct {
+    BYTE Dev;
+    BYTE Bus:6;
+    BYTE Mode:2;        /* b00 */
+  } PeripDev;
+   struct {
+    BYTE DevLSB;
+    BYTE DevMSB:6;
+    BYTE Mode:2;        /* b01 */
+  } LogDev;
+   struct {
+    BYTE Dev:5;
+    BYTE Bus:3;
+    BYTE Targ:6;
+    BYTE Mode:2;        /* b10 */
+  } LogUnit;
+} SCSI3Addr_struct;
+
+typedef struct _PhysDevAddr_struct {
+  DWORD             TargetId:24;
+  DWORD             Bus:6;
+  DWORD             Mode:2;
+  SCSI3Addr_struct  Target[2]; /* 2 level target device addr */
+} PhysDevAddr_struct;
+
+typedef struct _LogDevAddr_struct {
+  DWORD            VolId:30;
+  DWORD            Mode:2;
+  BYTE             reserved[4];
+} LogDevAddr_struct;
+
+typedef union _LUNAddr_struct {
+  BYTE               LunAddrBytes[8];
+  SCSI3Addr_struct   SCSI3Lun[4];
+  PhysDevAddr_struct PhysDev;
+  LogDevAddr_struct  LogDev;
+} LUNAddr_struct;
+
+typedef struct _RequestBlock_struct {
+  BYTE   CDBLen;
+  struct {
+    BYTE Type:3;
+    BYTE Attribute:3;
+    BYTE Direction:2;
+  } Type;
+  HWORD  Timeout;
+  BYTE   CDB[16];
+} RequestBlock_struct;
+
+typedef union _MoreErrInfo_struct{
+  struct {
+    BYTE  Reserved[3];
+    BYTE  Type;
+    DWORD ErrorInfo;
+  } Common_Info;
+  struct{
+    BYTE  Reserved[2];
+    BYTE  offense_size; /* size of offending entry */
+    BYTE  offense_num;  /* byte # of offense 0-base */
+    DWORD offense_value;
+  } Invalid_Cmd;
+} MoreErrInfo_struct;
+typedef struct _ErrorInfo_struct {
+  BYTE               ScsiStatus;
+  BYTE               SenseLen;
+  HWORD              CommandStatus;
+  DWORD              ResidualCnt;
+  MoreErrInfo_struct MoreErrInfo;
+  BYTE               SenseInfo[SENSEINFOBYTES];
+} ErrorInfo_struct;
+
+#pragma pack()
+
+#endif /* CCISS_DEFS_H */
index eb130b4d8e720a04307d3442a6600a08bea5f53c..986493f5b92ba2c31875c42f78954a5baf4148c4 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/types.h>
 #include <linux/ioctl.h>
+#include <linux/cciss_defs.h>
 
 #define CCISS_IOC_MAGIC 'B'
 
@@ -36,133 +37,6 @@ typedef __u32 DriverVer_type;
 
 #define MAX_KMALLOC_SIZE 128000
 
-#ifndef CCISS_CMD_H
-// This defines are duplicated in cciss_cmd.h in the driver directory 
-
-//general boundary definitions
-#define SENSEINFOBYTES          32//note that this value may vary between host implementations
-
-//Command Status value
-#define CMD_SUCCESS             0x0000
-#define CMD_TARGET_STATUS       0x0001
-#define CMD_DATA_UNDERRUN       0x0002
-#define CMD_DATA_OVERRUN        0x0003
-#define CMD_INVALID             0x0004
-#define CMD_PROTOCOL_ERR        0x0005
-#define CMD_HARDWARE_ERR        0x0006
-#define CMD_CONNECTION_LOST     0x0007
-#define CMD_ABORTED             0x0008
-#define CMD_ABORT_FAILED        0x0009
-#define CMD_UNSOLICITED_ABORT   0x000A
-#define CMD_TIMEOUT             0x000B
-#define CMD_UNABORTABLE                0x000C
-
-//transfer direction
-#define XFER_NONE               0x00
-#define XFER_WRITE              0x01
-#define XFER_READ               0x02
-#define XFER_RSVD               0x03
-
-//task attribute
-#define ATTR_UNTAGGED           0x00
-#define ATTR_SIMPLE             0x04
-#define ATTR_HEADOFQUEUE        0x05
-#define ATTR_ORDERED            0x06
-#define ATTR_ACA                0x07
-
-//cdb type
-#define TYPE_CMD                               0x00
-#define TYPE_MSG                               0x01
-
-// Type defs used in the following structs
-#define BYTE __u8
-#define WORD __u16
-#define HWORD __u16
-#define DWORD __u32
-
-#define CISS_MAX_LUN   1024
-
-#define LEVEL2LUN   1   // index into Target(x) structure, due to byte swapping
-#define LEVEL3LUN   0
-
-#pragma pack(1)
-
-//Command List Structure
-typedef union _SCSI3Addr_struct {
-   struct {
-    BYTE Dev;
-    BYTE Bus:6;
-    BYTE Mode:2;        // b00
-  } PeripDev;
-   struct {
-    BYTE DevLSB;
-    BYTE DevMSB:6;
-    BYTE Mode:2;        // b01
-  } LogDev;
-   struct {
-    BYTE Dev:5;
-    BYTE Bus:3;
-    BYTE Targ:6;
-    BYTE Mode:2;        // b10
-  } LogUnit;
-} SCSI3Addr_struct;
-
-typedef struct _PhysDevAddr_struct {
-  DWORD             TargetId:24;
-  DWORD             Bus:6;
-  DWORD             Mode:2;
-  SCSI3Addr_struct  Target[2]; //2 level target device addr
-} PhysDevAddr_struct;
-  
-typedef struct _LogDevAddr_struct {
-  DWORD            VolId:30;
-  DWORD            Mode:2;
-  BYTE             reserved[4];
-} LogDevAddr_struct;
-
-typedef union _LUNAddr_struct {
-  BYTE               LunAddrBytes[8];
-  SCSI3Addr_struct   SCSI3Lun[4];
-  PhysDevAddr_struct PhysDev;
-  LogDevAddr_struct  LogDev;
-} LUNAddr_struct;
-
-typedef struct _RequestBlock_struct {
-  BYTE   CDBLen;
-  struct {
-    BYTE Type:3;
-    BYTE Attribute:3;
-    BYTE Direction:2;
-  } Type;
-  HWORD  Timeout;
-  BYTE   CDB[16];
-} RequestBlock_struct;
-
-typedef union _MoreErrInfo_struct{
-  struct {
-    BYTE  Reserved[3];
-    BYTE  Type;
-    DWORD ErrorInfo;
-  }Common_Info;
-  struct{
-    BYTE  Reserved[2];
-    BYTE  offense_size;//size of offending entry
-    BYTE  offense_num; //byte # of offense 0-base
-    DWORD offense_value;
-  }Invalid_Cmd;
-}MoreErrInfo_struct;
-typedef struct _ErrorInfo_struct {
-  BYTE               ScsiStatus;
-  BYTE               SenseLen;
-  HWORD              CommandStatus;
-  DWORD              ResidualCnt;
-  MoreErrInfo_struct MoreErrInfo;
-  BYTE               SenseInfo[SENSEINFOBYTES];
-} ErrorInfo_struct;
-
-#pragma pack()
-#endif /* CCISS_CMD_H */ 
-
 typedef struct _IOCTL_Command_struct {
   LUNAddr_struct          LUN_info;
   RequestBlock_struct      Request;
index 8a4a130cc19698ab8a03c6c6344e3b24f42932f8..4bca8b60cdf79c52b30a53add160ab7e0c0bfa3d 100644 (file)
@@ -154,6 +154,7 @@ extern u64 timecounter_cyc2time(struct timecounter *tc,
  * @max_idle_ns:       max idle time permitted by the clocksource (nsecs)
  * @flags:             flags describing special properties
  * @vread:             vsyscall based read
+ * @suspend:           suspend function for the clocksource, if necessary
  * @resume:            resume function for the clocksource, if necessary
  */
 struct clocksource {
@@ -172,7 +173,8 @@ struct clocksource {
        u64 max_idle_ns;
        unsigned long flags;
        cycle_t (*vread)(void);
-       void (*resume)(void);
+       void (*suspend)(struct clocksource *cs);
+       void (*resume)(struct clocksource *cs);
 #ifdef CONFIG_IA64
        void *fsys_mmio;        /* used by fsyscall asm code */
 #define CLKSRC_FSYS_MMIO_SET(mmio, addr)      ((mmio) = (addr))
@@ -277,6 +279,7 @@ extern void clocksource_unregister(struct clocksource*);
 extern void clocksource_touch_watchdog(void);
 extern struct clocksource* clocksource_get_next(void);
 extern void clocksource_change_rating(struct clocksource *cs, int rating);
+extern void clocksource_suspend(void);
 extern void clocksource_resume(void);
 extern struct clocksource * __init __weak clocksource_default_clock(void);
 extern void clocksource_mark_unstable(struct clocksource *cs);
similarity index 83%
rename from arch/arm/mach-davinci/include/mach/emac.h
rename to include/linux/davinci_emac.h
index beff4fb7c845238db3dc2d4aa0dd05e0ee4c8f4e..7c930dba477ca2da1d748ac66bc157f5d0887052 100644 (file)
@@ -8,8 +8,8 @@
  * is licensed "as is" without any warranty of any kind, whether express
  * or implied.
  */
-#ifndef _MACH_DAVINCI_EMAC_H
-#define _MACH_DAVINCI_EMAC_H
+#ifndef _LINUX_DAVINCI_EMAC_H
+#define _LINUX_DAVINCI_EMAC_H
 
 #include <linux/if_ether.h>
 #include <linux/memory.h>
@@ -19,12 +19,15 @@ struct emac_platform_data {
        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;
        u8 rmii_en;
        u8 version;
+       void (*interrupt_enable) (void);
+       void (*interrupt_disable) (void);
 };
 
 enum {
index 1bc08541c2b9cff63e3ae58267244321034edb5b..48e68da097f6f50000b80e8dd10a82581233179b 100644 (file)
@@ -46,7 +46,6 @@ struct gameport {
        struct mutex drv_mutex;         /* protects serio->drv so attributes can pin driver */
 
        struct device dev;
-       unsigned int registered;        /* port has been fully registered with driver core */
 
        struct list_head node;
 };
index 1289fa7623ca22d7d79188bc39cf5b5b35c180b1..cd0b3f30f48ed1bc8294ac759bf7965b3efce851 100644 (file)
@@ -10,6 +10,7 @@ struct gpio_keys_button {
        int type;               /* input event type (EV_KEY, EV_SW) */
        int wakeup;             /* configure the button as a wake-up source */
        int debounce_interval;  /* debounce ticks interval in msecs */
+       bool can_disable;
 };
 
 struct gpio_keys_platform_data {
index 9eb07bbc6522bb4508797a7468a22ba465894e34..a87124d4d5338d2704875c71ba5f6d87c8d41a72 100644 (file)
@@ -12,9 +12,8 @@
 #ifndef __I2C_PNX_H__
 #define __I2C_PNX_H__
 
-#include <linux/pm.h>
-
 struct platform_device;
+struct clk;
 
 struct i2c_pnx_mif {
        int                     ret;            /* Return value */
@@ -26,20 +25,18 @@ struct i2c_pnx_mif {
 };
 
 struct i2c_pnx_algo_data {
-       u32                     base;
-       u32                     ioaddr;
-       int                     irq;
+       void __iomem            *ioaddr;
        struct i2c_pnx_mif      mif;
        int                     last;
+       struct clk              *clk;
+       struct i2c_pnx_data     *i2c_pnx;
+       struct i2c_adapter      adapter;
 };
 
 struct i2c_pnx_data {
-       int (*suspend) (struct platform_device *pdev, pm_message_t state);
-       int (*resume) (struct platform_device *pdev);
-       u32 (*calculate_input_freq) (struct platform_device *pdev);
-       int (*set_clock_run) (struct platform_device *pdev);
-       int (*set_clock_stop) (struct platform_device *pdev);
-       struct i2c_adapter *adapter;
+       const char *name;
+       u32 base;
+       int irq;
 };
 
 #endif /* __I2C_PNX_H__ */
index bf1c5be1f5b66879e238ff6605c17b4787f13ffc..7897f309656086be6db77189efdd94639128d116 100644 (file)
@@ -547,6 +547,10 @@ struct twl4030_codec_data {
        unsigned int    audio_mclk;
        struct twl4030_codec_audio_data         *audio;
        struct twl4030_codec_vibra_data         *vibra;
+
+       /* twl6030 */
+       int audpwron_gpio;      /* audio power-on gpio */
+       int naudint_irq;        /* audio interrupt */
 };
 
 struct twl4030_platform_data {
index 4c4e57d1f19d74c245c7e70e09c5e9428f838089..87018dc5527dac26d9baf1eefd000b56f74509ff 100644 (file)
 /* defines for max_sectors and max_phys_segments */
 #define I2O_MAX_SECTORS                        1024
 #define I2O_MAX_SECTORS_LIMITED                128
-#define I2O_MAX_PHYS_SEGMENTS          MAX_PHYS_SEGMENTS
+#define I2O_MAX_PHYS_SEGMENTS          BLK_MAX_SEGMENTS
 
 /*
  *     Message structures
index f44ee9114401777eb5f0628a03fa074084a23ca9..dc24effb6d0e71816d33d6501304aca44c879a86 100644 (file)
@@ -378,7 +378,7 @@ struct input_absinfo {
 #define KEY_WIMAX              246
 #define KEY_RFKILL             247     /* Key that controls all radios */
 
-/* Range 248 - 255 is reserved for special needs of AT keyboard driver */
+/* Code 255 is reserved for special needs of AT keyboard driver */
 
 #define BTN_MISC               0x100
 #define BTN_0                  0x100
@@ -597,6 +597,7 @@ struct input_absinfo {
 #define KEY_NUMERIC_POUND      0x20b
 
 #define KEY_CAMERA_FOCUS       0x210
+#define KEY_WPS_BUTTON         0x211   /* WiFi Protected Setup key */
 
 #define BTN_TRIGGER_HAPPY              0x2c0
 #define BTN_TRIGGER_HAPPY1             0x2c0
@@ -1242,6 +1243,10 @@ struct input_handle;
  * @event: event handler. This method is being called by input core with
  *     interrupts disabled and dev->event_lock spinlock held and so
  *     it may not sleep
+ * @filter: similar to @event; separates normal event handlers from
+ *     "filters".
+ * @match: called after comparing device's id with handler's id_table
+ *     to perform fine-grained matching between device and handler
  * @connect: called when attaching a handler to an input device
  * @disconnect: disconnects a handler from input device
  * @start: starts handler for given handle. This function is called by
@@ -1253,8 +1258,6 @@ struct input_handle;
  * @name: name of the handler, to be shown in /proc/bus/input/handlers
  * @id_table: pointer to a table of input_device_ids this driver can
  *     handle
- * @blacklist: pointer to a table of input_device_ids this driver should
- *     ignore even if they match @id_table
  * @h_list: list of input handles associated with the handler
  * @node: for placing the driver onto input_handler_list
  *
@@ -1263,6 +1266,11 @@ struct input_handle;
  * same time. All of them will get their copy of input event generated by
  * the device.
  *
+ * The very same structure is used to implement input filters. Input core
+ * allows filters to run first and will not pass event to regular handlers
+ * if any of the filters indicate that the event should be filtered (by
+ * returning %true from their filter() method).
+ *
  * Note that input core serializes calls to connect() and disconnect()
  * methods.
  */
@@ -1271,6 +1279,8 @@ struct input_handler {
        void *private;
 
        void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
+       bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
+       bool (*match)(struct input_handler *handler, struct input_dev *dev);
        int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
        void (*disconnect)(struct input_handle *handle);
        void (*start)(struct input_handle *handle);
@@ -1280,7 +1290,6 @@ struct input_handler {
        const char *name;
 
        const struct input_device_id *id_table;
-       const struct input_device_id *blacklist;
 
        struct list_head        h_list;
        struct list_head        node;
index c211b5cf08e673890f91ef6a3f18ff371a40d5f6..649dc7f12925d0ac7a9152e7e9f7e79b269b3ec6 100644 (file)
@@ -1,14 +1,15 @@
 #ifndef __SH_KEYSC_H__
 #define __SH_KEYSC_H__
 
-#define SH_KEYSC_MAXKEYS 30
+#define SH_KEYSC_MAXKEYS 49
 
 struct sh_keysc_info {
-       enum { SH_KEYSC_MODE_1, SH_KEYSC_MODE_2, SH_KEYSC_MODE_3 } mode;
+       enum { SH_KEYSC_MODE_1, SH_KEYSC_MODE_2, SH_KEYSC_MODE_3,
+              SH_KEYSC_MODE_4, SH_KEYSC_MODE_5, SH_KEYSC_MODE_6 } mode;
        int scan_timing; /* 0 -> 7, see KYCR1, SCN[2:0] */
        int delay;
        int kycr2_delay;
-       int keycodes[SH_KEYSC_MAXKEYS];
+       int keycodes[SH_KEYSC_MAXKEYS]; /* KEYIN * KEYOUT */
 };
 
 #endif /* __SH_KEYSC_H__ */
index 78ef023227d4bbcabc5e5d72d3126462c9b9ca26..1195a806fe0cd7eec9915e616141c76db564d538 100644 (file)
@@ -49,8 +49,8 @@ struct io_context {
        /*
         * For request batching
         */
-       unsigned long last_waited; /* Time last woken after wait for request */
        int nr_batch_requests;     /* Number of requests left in the batch */
+       unsigned long last_waited; /* Time last woken after wait for request */
 
        struct radix_tree_root radix_root;
        struct hlist_head cic_list;
index 451481c082b55c3f571e4dadc1d2b7b386bdfa9a..d13492df57a1bb9c55dd51085b6518aae5557208 100644 (file)
@@ -90,7 +90,7 @@ struct msi_desc;
  * @startup:           start up the interrupt (defaults to ->enable if NULL)
  * @shutdown:          shut down the interrupt (defaults to ->disable if NULL)
  * @enable:            enable the interrupt (defaults to chip->unmask if NULL)
- * @disable:           disable the interrupt (defaults to chip->mask if NULL)
+ * @disable:           disable the interrupt
  * @ack:               start of a new interrupt
  * @mask:              mask an interrupt source
  * @mask_ack:          ack and mask an interrupt source
index 8bdb16bfe5fb698eb2d8e0a0fe8c6785434e53d0..506ad20c18f8736b355530cc01fa91ca149fe322 100644 (file)
@@ -161,7 +161,4 @@ static inline void con_schedule_flip(struct tty_struct *t)
        schedule_delayed_work(&t->buf.work, 0);
 }
 
-/* mac_hid.c */
-extern int mac_hid_mouse_emulate_buttons(int, unsigned int, int);
-
 #endif
index 73112250862c42d78a72b20d241d31a936c34844..f8ea71e6d0e2f52c4811d14de18ea7d231b37959 100644 (file)
@@ -857,6 +857,7 @@ struct ata_port_operations {
        unsigned int (*sff_data_xfer)(struct ata_device *dev,
                        unsigned char *buf, unsigned int buflen, int rw);
        u8   (*sff_irq_on)(struct ata_port *);
+       bool (*sff_irq_check)(struct ata_port *);
        void (*sff_irq_clear)(struct ata_port *);
 
        void (*bmdma_setup)(struct ata_queued_cmd *qc);
@@ -1642,8 +1643,8 @@ extern int ata_pci_sff_activate_host(struct ata_host *host,
                                     irq_handler_t irq_handler,
                                     struct scsi_host_template *sht);
 extern int ata_pci_sff_init_one(struct pci_dev *pdev,
-                               const struct ata_port_info * const * ppi,
-                               struct scsi_host_template *sht, void *host_priv);
+               const struct ata_port_info * const * ppi,
+               struct scsi_host_template *sht, void *host_priv, int hflags);
 #endif /* CONFIG_PCI */
 
 /**
index 76e5053e1fac8f76ca5942e90e62b166037ded53..721301b0a9087c27a22a48e49e16b795fc975073 100644 (file)
@@ -163,10 +163,8 @@ struct packet_iosched
        atomic_t                attention;      /* Set to non-zero when queue processing is needed */
        int                     writing;        /* Non-zero when writing, zero when reading */
        spinlock_t              lock;           /* Protecting read/write queue manipulations */
-       struct bio              *read_queue;
-       struct bio              *read_queue_tail;
-       struct bio              *write_queue;
-       struct bio              *write_queue_tail;
+       struct bio_list         read_queue;
+       struct bio_list         write_queue;
        sector_t                last_write;     /* The sector where the last write ended */
        int                     successive_reads;
 };
@@ -206,8 +204,8 @@ struct packet_data
        spinlock_t              lock;           /* Lock protecting state transitions and */
                                                /* orig_bios list */
 
-       struct bio              *orig_bios;     /* Original bios passed to pkt_make_request */
-       struct bio              *orig_bios_tail;/* that will be handled by this packet */
+       struct bio_list         orig_bios;      /* Original bios passed to pkt_make_request */
+                                               /* that will be handled by this packet */
        int                     write_size;     /* Total size of all bios in the orig_bios */
                                                /* list, measured in number of frames */
 
index 0eef87b58ea5271bdc3d904324ce0c788fbc6c49..4b1753f7e48e328a0811de88f8e0978fdb87f490 100644 (file)
@@ -97,7 +97,7 @@ struct sched_param {
 struct exec_domain;
 struct futex_pi_state;
 struct robust_list_head;
-struct bio;
+struct bio_list;
 struct fs_struct;
 struct bts_context;
 struct perf_event_context;
@@ -1454,7 +1454,7 @@ struct task_struct {
        void *journal_info;
 
 /* stacked block device info */
-       struct bio *bio_list, **bio_tail;
+       struct bio_list *bio_list;
 
 /* VM state */
        struct reclaim_state *reclaim_state;
index 813d26c247ece48b709a14a427f655a2c04442fc..64b473066b9aa49760d67c2d45eb695cbf0d812e 100644 (file)
@@ -30,7 +30,6 @@ struct serio {
        char phys[32];
 
        bool manual_bind;
-       bool registered;        /* port has been fully registered with driver core */
 
        struct serio_device_id id;
 
index 94f8faecdcbc75bc9a10ffc9fb2a97465480b76e..7a082b32d8e13ac98fe5b04b962f2f44a4f9ecc7 100644 (file)
@@ -238,9 +238,6 @@ extern int tickadj;                 /* amount of adjustment per tick */
  * phase-lock loop variables
  */
 extern int time_status;                /* clock synchronization status bits */
-extern long time_maxerror;     /* maximum error */
-extern long time_esterror;     /* estimated error */
-
 extern long time_adjust;       /* The amount of adjtime left */
 
 extern void ntp_init(void);
index eaf9dffe0a01bea235e5b4be98aa3d49b4120e59..6bb293684eb893265da0184c9618ea03c0a00924 100644 (file)
@@ -25,6 +25,9 @@
 #define USB_SUBCLASS_AUDIOSTREAMING    0x02
 #define USB_SUBCLASS_MIDISTREAMING     0x03
 
+#define UAC_VERSION_1                  0x00
+#define UAC_VERSION_2                  0x20
+
 /* A.5 Audio Class-Specific AC Interface Descriptor Subtypes */
 #define UAC_HEADER                     0x01
 #define UAC_INPUT_TERMINAL             0x02
 #define UAC_MIXER_UNIT                 0x04
 #define UAC_SELECTOR_UNIT              0x05
 #define UAC_FEATURE_UNIT               0x06
-#define UAC_PROCESSING_UNIT            0x07
-#define UAC_EXTENSION_UNIT             0x08
+#define UAC_PROCESSING_UNIT_V1         0x07
+#define UAC_EXTENSION_UNIT_V1          0x08
+
+/* UAC v2.0 types */
+#define UAC_EFFECT_UNIT                        0x07
+#define UAC_PROCESSING_UNIT_V2         0x08
+#define UAC_EXTENSION_UNIT_V2          0x09
+#define UAC_CLOCK_SOURCE               0x0a
+#define UAC_CLOCK_SELECTOR             0x0b
+#define UAC_CLOCK_MULTIPLIER           0x0c
+#define UAC_SAMPLE_RATE_CONVERTER      0x0d
 
 /* A.6 Audio Class-Specific AS Interface Descriptor Subtypes */
 #define UAC_AS_GENERAL                 0x01
 
 #define UAC_GET_STAT                   0xff
 
+/* Audio class v2.0 handles all the parameter calls differently */
+#define UAC2_CS_CUR                    0x01
+#define UAC2_CS_RANGE                  0x02
+
 /* MIDI - A.1 MS Class-Specific Interface Descriptor Subtypes */
 #define UAC_MS_HEADER                  0x01
 #define UAC_MIDI_IN_JACK               0x02
@@ -81,7 +97,7 @@
 
 /* Terminal Control Selectors */
 /* 4.3.2  Class-Specific AC Interface Descriptor */
-struct uac_ac_header_descriptor {
+struct uac_ac_header_descriptor_v1 {
        __u8  bLength;                  /* 8 + n */
        __u8  bDescriptorType;          /* USB_DT_CS_INTERFACE */
        __u8  bDescriptorSubtype;       /* UAC_MS_HEADER */
@@ -95,7 +111,7 @@ struct uac_ac_header_descriptor {
 
 /* As above, but more useful for defining your own descriptors: */
 #define DECLARE_UAC_AC_HEADER_DESCRIPTOR(n)                    \
-struct uac_ac_header_descriptor_##n {                          \
+struct uac_ac_header_descriptor_v1_##n {                       \
        __u8  bLength;                                          \
        __u8  bDescriptorType;                                  \
        __u8  bDescriptorSubtype;                               \
@@ -130,8 +146,12 @@ struct uac_input_terminal_descriptor {
 #define UAC_INPUT_TERMINAL_MICROPHONE_ARRAY            0x205
 #define UAC_INPUT_TERMINAL_PROC_MICROPHONE_ARRAY       0x206
 
+/* Terminals - control selectors */
+
+#define UAC_TERMINAL_CS_COPY_PROTECT_CONTROL           0x01
+
 /* 4.3.2.2 Output Terminal Descriptor */
-struct uac_output_terminal_descriptor {
+struct uac_output_terminal_descriptor_v1 {
        __u8  bLength;                  /* in bytes: 9 */
        __u8  bDescriptorType;          /* CS_INTERFACE descriptor type */
        __u8  bDescriptorSubtype;       /* OUTPUT_TERMINAL descriptor subtype */
@@ -171,7 +191,7 @@ struct uac_feature_unit_descriptor_##ch {                   \
 } __attribute__ ((packed))
 
 /* 4.5.2 Class-Specific AS Interface Descriptor */
-struct uac_as_header_descriptor {
+struct uac_as_header_descriptor_v1 {
        __u8  bLength;                  /* in bytes: 7 */
        __u8  bDescriptorType;          /* USB_DT_CS_INTERFACE */
        __u8  bDescriptorSubtype;       /* AS_GENERAL */
@@ -180,6 +200,19 @@ struct uac_as_header_descriptor {
        __le16 wFormatTag;              /* The Audio Data Format */
 } __attribute__ ((packed));
 
+struct uac_as_header_descriptor_v2 {
+       __u8 bLength;
+       __u8 bDescriptorType;
+       __u8 bDescriptorSubtype;
+       __u8 bTerminalLink;
+       __u8 bmControls;
+       __u8 bFormatType;
+       __u32 bmFormats;
+       __u8 bNrChannels;
+       __u32 bmChannelConfig;
+       __u8 iChannelNames;
+} __attribute__((packed));
+
 #define UAC_DT_AS_HEADER_SIZE          7
 
 /* Formats - A.1.1 Audio Data Format Type I Codes */
@@ -232,11 +265,62 @@ struct uac_format_type_i_discrete_descriptor_##n {                \
 
 #define UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(n)        (8 + (n * 3))
 
+struct uac_format_type_i_ext_descriptor {
+       __u8 bLength;
+       __u8 bDescriptorType;
+       __u8 bDescriptorSubtype;
+       __u8 bSubslotSize;
+       __u8 bFormatType;
+       __u8 bBitResolution;
+       __u8 bHeaderLength;
+       __u8 bControlSize;
+       __u8 bSideBandProtocol;
+} __attribute__((packed));
+
+
+/* Formats - Audio Data Format Type I Codes */
+
+#define UAC_FORMAT_TYPE_II_MPEG        0x1001
+#define UAC_FORMAT_TYPE_II_AC3 0x1002
+
+struct uac_format_type_ii_discrete_descriptor {
+       __u8 bLength;
+       __u8 bDescriptorType;
+       __u8 bDescriptorSubtype;
+       __u8 bFormatType;
+       __le16 wMaxBitRate;
+       __le16 wSamplesPerFrame;
+       __u8 bSamFreqType;
+       __u8 tSamFreq[][3];
+} __attribute__((packed));
+
+struct uac_format_type_ii_ext_descriptor {
+       __u8 bLength;
+       __u8 bDescriptorType;
+       __u8 bDescriptorSubtype;
+       __u8 bFormatType;
+       __u16 wMaxBitRate;
+       __u16 wSamplesPerFrame;
+       __u8 bHeaderLength;
+       __u8 bSideBandProtocol;
+} __attribute__((packed));
+
+/* type III */
+#define UAC_FORMAT_TYPE_III_IEC1937_AC3        0x2001
+#define UAC_FORMAT_TYPE_III_IEC1937_MPEG1_LAYER1       0x2002
+#define UAC_FORMAT_TYPE_III_IEC1937_MPEG2_NOEXT        0x2003
+#define UAC_FORMAT_TYPE_III_IEC1937_MPEG2_EXT  0x2004
+#define UAC_FORMAT_TYPE_III_IEC1937_MPEG2_LAYER1_LS    0x2005
+#define UAC_FORMAT_TYPE_III_IEC1937_MPEG2_LAYER23_LS   0x2006
+
 /* Formats - A.2 Format Type Codes */
 #define UAC_FORMAT_TYPE_UNDEFINED      0x0
 #define UAC_FORMAT_TYPE_I              0x1
 #define UAC_FORMAT_TYPE_II             0x2
 #define UAC_FORMAT_TYPE_III            0x3
+#define UAC_EXT_FORMAT_TYPE_I          0x81
+#define UAC_EXT_FORMAT_TYPE_II         0x82
+#define UAC_EXT_FORMAT_TYPE_III                0x83
 
 struct uac_iso_endpoint_descriptor {
        __u8  bLength;                  /* in bytes: 7 */
@@ -252,7 +336,31 @@ struct uac_iso_endpoint_descriptor {
 #define UAC_EP_CS_ATTR_PITCH_CONTROL   0x02
 #define UAC_EP_CS_ATTR_FILL_MAX                0x80
 
+/* Audio class v2.0: CLOCK_SOURCE descriptor */
+
+struct uac_clock_source_descriptor {
+       __u8 bLength;
+       __u8 bDescriptorType;
+       __u8 bDescriptorSubtype;
+       __u8 bClockID;
+       __u8 bmAttributes;
+       __u8 bmControls;
+       __u8 bAssocTerminal;
+       __u8 iClockSource;
+} __attribute__((packed));
+
 /* A.10.2 Feature Unit Control Selectors */
+
+struct uac_feature_unit_descriptor {
+       __u8 bLength;
+       __u8 bDescriptorType;
+       __u8 bDescriptorSubtype;
+       __u8 bUnitID;
+       __u8 bSourceID;
+       __u8 bControlSize;
+       __u8 controls[0]; /* variable length */
+} __attribute__((packed));
+
 #define UAC_FU_CONTROL_UNDEFINED       0x00
 #define UAC_MUTE_CONTROL               0x01
 #define UAC_VOLUME_CONTROL             0x02
index a61499c22b0b96044314048791b3152e5249d98e..89e0ac17f44a1c461bd8b1cdc565f99b8eeb4217 100644 (file)
@@ -458,5 +458,8 @@ struct snd_pci_quirk {
 const struct snd_pci_quirk *
 snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list);
 
+const struct snd_pci_quirk *
+snd_pci_quirk_lookup_id(u16 vendor, u16 device,
+                       const struct snd_pci_quirk *list);
 
 #endif /* __SOUND_CORE_H */
index 7c44667e79a6498bb1137d4dcc3e11a3a78a342c..49b03c9e5e551554b71640fb3dd397beb4c28a06 100644 (file)
@@ -118,9 +118,11 @@ struct dsp_scb_descriptor {
 
        struct snd_info_entry *proc_info;
        int ref_count;
-       spinlock_t lock;
 
-       int deleted;
+       u16 volume[2];
+       unsigned int deleted :1;
+       unsigned int updated :1;
+       unsigned int volume_set :1;
 };
 
 struct dsp_task_descriptor {
index c83a4a79f16b2646279fa1e68e7516bd73f2c122..8b611a561985a8350c217d160f167cb4d224d01a 100644 (file)
@@ -262,6 +262,8 @@ struct snd_pcm_hw_constraint_list {
        unsigned int mask;
 };
 
+struct snd_pcm_hwptr_log;
+
 struct snd_pcm_runtime {
        /* -- Status -- */
        struct snd_pcm_substream *trigger_master;
@@ -310,7 +312,9 @@ struct snd_pcm_runtime {
        struct snd_pcm_mmap_control *control;
 
        /* -- locking / scheduling -- */
-       wait_queue_head_t sleep;
+       unsigned int twake: 1;          /* do transfer (!poll) wakeup */
+       wait_queue_head_t sleep;        /* poll sleep */
+       wait_queue_head_t tsleep;       /* transfer sleep */
        struct fasync_struct *fasync;
 
        /* -- private section -- */
@@ -340,6 +344,10 @@ struct snd_pcm_runtime {
        /* -- OSS things -- */
        struct snd_pcm_oss_runtime oss;
 #endif
+
+#ifdef CONFIG_SND_PCM_XRUN_DEBUG
+       struct snd_pcm_hwptr_log *hwptr_log;
+#endif
 };
 
 struct snd_pcm_group {         /* keep linked substreams */
@@ -834,6 +842,8 @@ void snd_pcm_set_sync(struct snd_pcm_substream *substream);
 int snd_pcm_lib_interleave_len(struct snd_pcm_substream *substream);
 int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
                      unsigned int cmd, void *arg);                      
+int snd_pcm_update_state(struct snd_pcm_substream *substream,
+                        struct snd_pcm_runtime *runtime);
 int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream);
 int snd_pcm_playback_xrun_check(struct snd_pcm_substream *substream);
 int snd_pcm_capture_xrun_check(struct snd_pcm_substream *substream);
@@ -905,6 +915,44 @@ int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm,
 int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size);
 int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream);
 
+int _snd_pcm_lib_alloc_vmalloc_buffer(struct snd_pcm_substream *substream,
+                                     size_t size, gfp_t gfp_flags);
+int snd_pcm_lib_free_vmalloc_buffer(struct snd_pcm_substream *substream);
+struct page *snd_pcm_lib_get_vmalloc_page(struct snd_pcm_substream *substream,
+                                         unsigned long offset);
+#if 0 /* for kernel-doc */
+/**
+ * snd_pcm_lib_alloc_vmalloc_buffer - allocate virtual DMA buffer
+ * @substream: the substream to allocate the buffer to
+ * @size: the requested buffer size, in bytes
+ *
+ * Allocates the PCM substream buffer using vmalloc(), i.e., the memory is
+ * contiguous in kernel virtual space, but not in physical memory.  Use this
+ * if the buffer is accessed by kernel code but not by device DMA.
+ *
+ * Returns 1 if the buffer was changed, 0 if not changed, or a negative error
+ * code.
+ */
+static int snd_pcm_lib_alloc_vmalloc_buffer
+                       (struct snd_pcm_substream *substream, size_t size);
+/**
+ * snd_pcm_lib_alloc_vmalloc_32_buffer - allocate 32-bit-addressable buffer
+ * @substream: the substream to allocate the buffer to
+ * @size: the requested buffer size, in bytes
+ *
+ * This function works like snd_pcm_lib_alloc_vmalloc_buffer(), but uses
+ * vmalloc_32(), i.e., the pages are allocated from 32-bit-addressable memory.
+ */
+static int snd_pcm_lib_alloc_vmalloc_32_buffer
+                       (struct snd_pcm_substream *substream, size_t size);
+#endif
+#define snd_pcm_lib_alloc_vmalloc_buffer(subs, size) \
+       _snd_pcm_lib_alloc_vmalloc_buffer \
+                       (subs, size, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO)
+#define snd_pcm_lib_alloc_vmalloc_32_buffer(subs, size) \
+       _snd_pcm_lib_alloc_vmalloc_buffer \
+                       (subs, size, GFP_KERNEL | GFP_DMA32 | __GFP_ZERO)
+
 #ifdef CONFIG_SND_DMA_SGBUF
 /*
  * SG-buffer handling
@@ -975,6 +1023,10 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, struct vm_area_s
 #define snd_pcm_lib_mmap_iomem NULL
 #endif
 
+int snd_pcm_lib_mmap_noncached(struct snd_pcm_substream *substream,
+                              struct vm_area_struct *area);
+#define snd_pcm_lib_mmap_vmalloc       snd_pcm_lib_mmap_noncached
+
 static inline void snd_pcm_limit_isa_dma_size(int dma, size_t *max)
 {
        *max = dma < 4 ? 64 * 1024 : 128 * 1024;
index cc4e226f35fd5b07a4c0aebbea8ea282aa1309b7..760c969d885d542997010ad8486662fc35731088 100644 (file)
@@ -61,7 +61,7 @@ struct snd_pcm_oss_runtime {
        struct snd_pcm_plugin *plugin_first;
        struct snd_pcm_plugin *plugin_last;
 #endif
-       unsigned int prev_hw_ptr_interrupt;
+       unsigned int prev_hw_ptr_period;
 };
 
 struct snd_pcm_oss_file {
index 4e62ee1e4115222ad42c1fb52beea6c03b27da52..95353542256a2c69a9685460b49a853f8c8f5a7b 100644 (file)
@@ -33,6 +33,7 @@ enum sb_hw_type {
        SB_HW_20,
        SB_HW_201,
        SB_HW_PRO,
+       SB_HW_JAZZ16,           /* Media Vision Jazz16 */
        SB_HW_16,
        SB_HW_16CSP,            /* SB16 with CSP chip */
        SB_HW_ALS100,           /* Avance Logic ALS100 chip */
index ca24e7f7a3f5b83551efa2b1c62cfaba5991dd28..061f16d4c8780b18f15cafaefb760a5e0780af59 100644 (file)
@@ -16,6 +16,8 @@
 
 #include <linux/list.h>
 
+#include <sound/soc.h>
+
 struct snd_pcm_substream;
 
 /*
index c5c95e1da65b69752b44ba717e28d5e9dfb3caea..c0922a0342238bc1b9f10335710208467d83bc27 100644 (file)
        .shift = wshift, .invert = winvert, .kcontrols = wcontrols, \
        .num_kcontrols = 1}
 
+/* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
+#define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\
+        wcontrols) \
+{      .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
+       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
+#define SOC_MIXER_ARRAY(wname, wreg, wshift, winvert, \
+        wcontrols)\
+{      .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
+       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
+#define SOC_MIXER_NAMED_CTL_ARRAY(wname, wreg, wshift, winvert, \
+        wcontrols)\
+{       .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \
+       .shift = wshift, .invert = winvert, .kcontrols = wcontrols, \
+       .num_kcontrols = ARRAY_SIZE(wcontrols)}
+
 /* path domain with event - event handler must return 0 for success */
 #define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \
        wncontrols, wevent, wflags) \
        .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \
        .event = wevent, .event_flags = wflags}
 
+/* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
+#define SOC_PGA_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
+       wevent, wflags) \
+{      .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
+       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
+       .event = wevent, .event_flags = wflags}
+#define SOC_MIXER_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
+       wevent, wflags) \
+{      .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
+       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
+       .event = wevent, .event_flags = wflags}
+#define SOC_MIXER_NAMED_CTL_E_ARRAY(wname, wreg, wshift, winvert, \
+       wcontrols, wevent, wflags) \
+{       .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
+       .invert = winvert, .kcontrols = wcontrols, \
+       .num_kcontrols = ARRAY_SIZE(wcontrols), .event = wevent, .event_flags = wflags}
+
 /* events that are pre and post DAPM */
 #define SND_SOC_DAPM_PRE(wname, wevent) \
 {      .id = snd_soc_dapm_pre, .name = wname, .kcontrols = NULL, \
index 0d7718f9280db3e00e3da7e4232fa231510e0673..5d234a8c2506c74df25d5fbc7f9220c0bdb106ad 100644 (file)
        .get = xhandler_get, .put = xhandler_put, \
        .private_value = (unsigned long)&xenum }
 
+/*
+ * Simplified versions of above macros, declaring a struct and calculating
+ * ARRAY_SIZE internally
+ */
+#define SOC_ENUM_DOUBLE_DECL(name, xreg, xshift_l, xshift_r, xtexts) \
+       struct soc_enum name = SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, \
+                                               ARRAY_SIZE(xtexts), xtexts)
+#define SOC_ENUM_SINGLE_DECL(name, xreg, xshift, xtexts) \
+       SOC_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xtexts)
+#define SOC_ENUM_SINGLE_EXT_DECL(name, xtexts) \
+       struct soc_enum name = SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(xtexts), xtexts)
+#define SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift_l, xshift_r, xmask, xtexts, xvalues) \
+       struct soc_enum name = SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, \
+                                                       ARRAY_SIZE(xtexts), xtexts, xvalues)
+#define SOC_VALUE_ENUM_SINGLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \
+       SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xmask, xtexts, xvalues)
+
 /*
  * Bias levels
  *
@@ -253,6 +270,9 @@ void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
 /* codec register bit access */
 int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
                                unsigned int mask, unsigned int value);
+int snd_soc_update_bits_locked(struct snd_soc_codec *codec,
+                              unsigned short reg, unsigned int mask,
+                              unsigned int value);
 int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
                                unsigned int mask, unsigned int value);
 
@@ -402,6 +422,10 @@ struct snd_soc_codec {
        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;
        struct list_head dapm_widgets;
@@ -497,6 +521,8 @@ struct snd_soc_card {
        int (*set_bias_level)(struct snd_soc_card *,
                              enum snd_soc_bias_level level);
 
+       long pmdown_time;
+
        /* CPU <--> Codec DAI links  */
        struct snd_soc_dai_link *dai_link;
        int num_links;
index 5858d06a7ffa88c7ab2e2081d0cec8df925b1d57..ac0665264bdf1dcef855a45e54a586947fcbb09c 100644 (file)
@@ -15,6 +15,7 @@
 
 struct tlv320dac33_platform_data {
        int power_gpio;
+       u8 burst_bclkdiv;
 };
 
 #endif /* __TLV320DAC33_PLAT_H */
index e8c901e749d8f72cae77b3fe8ecd247aa2cf0faf..e29fde6b5cbe5214edeecbdc522c98afefd8a977 100644 (file)
 #ifndef TPA6130A2_PLAT_H
 #define TPA6130A2_PLAT_H
 
+enum tpa_model {
+       TPA6130A2,
+       TPA6140A2,
+};
+
 struct tpa6130a2_platform_data {
+       enum tpa_model id;
        int power_gpio;
 };
 
index 22939142dd236627796a248425702ffa6f413758..7fed23442db89f132b4e383d964875ccdf3f977d 100644 (file)
@@ -1,3 +1,3 @@
 /* include/version.h */
-#define CONFIG_SND_VERSION "1.0.21"
+#define CONFIG_SND_VERSION "1.0.22.1"
 #define CONFIG_SND_DATE ""
diff --git a/include/sound/wm2000.h b/include/sound/wm2000.h
new file mode 100644 (file)
index 0000000..aa388ca
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * linux/sound/wm2000.h -- Platform data for WM2000
+ *
+ * Copyright 2010 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_WM2000_H
+#define __LINUX_SND_WM2000_H
+
+struct wm2000_platform_data {
+       /** Filename for system-specific image to download to device. */
+       const char *download_file;
+
+       /** Divide MCLK by 2 for system clock? */
+       unsigned int mclkdiv2:1;
+
+       /** Disable speech clarity enhancement, for use when an
+        * external algorithm is used. */
+       unsigned int speech_enh_disable:1;
+};
+
+#endif
diff --git a/include/sound/wm8904.h b/include/sound/wm8904.h
new file mode 100644 (file)
index 0000000..d66575a
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Platform data for WM8904
+ *
+ * Copyright 2009 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 as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef __MFD_WM8994_PDATA_H__
+#define __MFD_WM8994_PDATA_H__
+
+#define WM8904_DRC_REGS 4
+#define WM8904_EQ_REGS  25
+
+/**
+ * DRC configurations are specified with a label and a set of register
+ * values to write (the enable bits will be ignored).  At runtime an
+ * enumerated control will be presented for each DRC block allowing
+ * the user to choose the configration to use.
+ *
+ * Configurations may be generated by hand or by using the DRC control
+ * panel provided by the WISCE - see  http://www.wolfsonmicro.com/wisce/
+ * for details.
+ */
+struct wm8904_drc_cfg {
+       const char *name;
+       u16 regs[WM8904_DRC_REGS];
+};
+
+/**
+ * ReTune Mobile configurations are specified with a label, sample
+ * rate and set of values to write (the enable bits will be ignored).
+ *
+ * Configurations are expected to be generated using the ReTune Mobile
+ * control panel in WISCE - see http://www.wolfsonmicro.com/wisce/
+ */
+struct wm8904_retune_mobile_cfg {
+       const char *name;
+       unsigned int rate;
+       u16 regs[WM8904_EQ_REGS];
+};
+
+struct wm8904_pdata {
+       int num_drc_cfgs;
+       struct wm8904_drc_cfg *drc_cfgs;
+
+       int num_retune_mobile_cfgs;
+       struct wm8904_retune_mobile_cfg *retune_mobile_cfgs;
+};
+
+#endif
diff --git a/include/sound/wm8955.h b/include/sound/wm8955.h
new file mode 100644 (file)
index 0000000..5074ef4
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Platform data for WM8955
+ *
+ * Copyright 2009 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 as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef __WM8955_PDATA_H__
+#define __WM8955_PDATA_H__
+
+struct wm8955_pdata {
+       /* Configure LOUT2/ROUT2 to drive a speaker */
+       unsigned int out2_speaker:1;
+
+       /* Configure MONOIN+/- in differential mode */
+       unsigned int monoin_diff:1;
+};
+
+#endif
index 235716556bf16ed9b97c19a9578ef24dec19edb1..d49afb2395e5cab17dd85417c95741c60c12a4cf 100644 (file)
@@ -146,7 +146,7 @@ compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr,
                struct task_struct *p;
 
                ret = -ESRCH;
-               read_lock(&tasklist_lock);
+               rcu_read_lock();
                p = find_task_by_vpid(pid);
                if (!p)
                        goto err_unlock;
@@ -157,7 +157,7 @@ compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr,
                    !capable(CAP_SYS_PTRACE))
                        goto err_unlock;
                head = p->compat_robust_list;
-               read_unlock(&tasklist_lock);
+               rcu_read_unlock();
        }
 
        if (put_user(sizeof(*head), len_ptr))
@@ -165,7 +165,7 @@ compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr,
        return put_user(ptr_to_compat(head), head_ptr);
 
 err_unlock:
-       read_unlock(&tasklist_lock);
+       rcu_read_unlock();
 
        return ret;
 }
index 495440779ce3b91c9927b98c61a83922b8578a31..00d1fda58ab6a270c42b7ad252e21ff36b4dce96 100644 (file)
@@ -256,7 +256,7 @@ static int posix_get_monotonic_coarse(clockid_t which_clock,
        return 0;
 }
 
-int posix_get_coarse_res(const clockid_t which_clock, struct timespec *tp)
+static int posix_get_coarse_res(const clockid_t which_clock, struct timespec *tp)
 {
        *tp = ktime_to_timespec(KTIME_LOW_RES);
        return 0;
index 13700833c181755f0f5a60e6fe34d53edb96448d..1f663d23e85e940d71716627d2de509143a88bfb 100644 (file)
@@ -452,6 +452,18 @@ static inline int clocksource_watchdog_kthread(void *data) { return 0; }
 
 #endif /* CONFIG_CLOCKSOURCE_WATCHDOG */
 
+/**
+ * clocksource_suspend - suspend the clocksource(s)
+ */
+void clocksource_suspend(void)
+{
+       struct clocksource *cs;
+
+       list_for_each_entry_reverse(cs, &clocksource_list, list)
+               if (cs->suspend)
+                       cs->suspend(cs);
+}
+
 /**
  * clocksource_resume - resume the clocksource(s)
  */
@@ -461,7 +473,7 @@ void clocksource_resume(void)
 
        list_for_each_entry(cs, &clocksource_list, list)
                if (cs->resume)
-                       cs->resume();
+                       cs->resume(cs);
 
        clocksource_resume_watchdog();
 }
index 4800f933910ea4ed8f0f2d8ad4d2f660eb4a3467..7c0f180d6e9d59053740fed37d39ae5374cb3720 100644 (file)
@@ -58,10 +58,10 @@ static s64                  time_offset;
 static long                    time_constant = 2;
 
 /* maximum error (usecs):                                              */
-long                           time_maxerror = NTP_PHASE_LIMIT;
+static long                    time_maxerror = NTP_PHASE_LIMIT;
 
 /* estimated error (usecs):                                            */
-long                           time_esterror = NTP_PHASE_LIMIT;
+static long                    time_esterror = NTP_PHASE_LIMIT;
 
 /* frequency offset (scaled nsecs/secs):                               */
 static s64                     time_freq;
@@ -142,11 +142,11 @@ static void ntp_update_offset(long offset)
         * Select how the frequency is to be controlled
         * and in which mode (PLL or FLL).
         */
-       secs = xtime.tv_sec - time_reftime;
+       secs = get_seconds() - time_reftime;
        if (unlikely(time_status & STA_FREQHOLD))
                secs = 0;
 
-       time_reftime = xtime.tv_sec;
+       time_reftime = get_seconds();
 
        offset64    = offset;
        freq_adj    = (offset64 * secs) <<
@@ -368,7 +368,7 @@ static inline void process_adj_status(struct timex *txc, struct timespec *ts)
         * reference time to current time.
         */
        if (!(time_status & STA_PLL) && (txc->status & STA_PLL))
-               time_reftime = xtime.tv_sec;
+               time_reftime = get_seconds();
 
        /* only set allowed bits */
        time_status &= STA_RONLY;
index e2ab064c6d418b21cc5467339f9a2a2e1909eb17..16736379a9caaba6320f32f3df6e94cb5a9abbda 100644 (file)
@@ -622,6 +622,7 @@ static int timekeeping_suspend(struct sys_device *dev, pm_message_t state)
        write_sequnlock_irqrestore(&xtime_lock, flags);
 
        clockevents_notify(CLOCK_EVT_NOTIFY_SUSPEND, NULL);
+       clocksource_suspend();
 
        return 0;
 }
index d9d6206e0b148f5c67e5ecda22a7c7992eec76d7..07f945a99430bfe58fd1dde80365a7e6e663147d 100644 (file)
@@ -540,9 +540,10 @@ int blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
        if (ret)
                return ret;
 
-       if (copy_to_user(arg, &buts, sizeof(buts)))
+       if (copy_to_user(arg, &buts, sizeof(buts))) {
+               blk_trace_remove(q);
                return -EFAULT;
-
+       }
        return 0;
 }
 EXPORT_SYMBOL_GPL(blk_trace_setup);
index 2d16fa6b8c2d8fb6a40ea5b3f9ea57c77a34d1af..3a5aeb37c1107ed9735b2e0e943db3212bacaf3c 100644 (file)
@@ -2087,7 +2087,7 @@ static void set_huge_ptep_writable(struct vm_area_struct *vma,
 
        entry = pte_mkwrite(pte_mkdirty(huge_ptep_get(ptep)));
        if (huge_ptep_set_access_flags(vma, address, ptep, entry, 1)) {
-               update_mmu_cache(vma, address, entry);
+               update_mmu_cache(vma, address, ptep);
        }
 }
 
@@ -2558,7 +2558,7 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
        entry = pte_mkyoung(entry);
        if (huge_ptep_set_access_flags(vma, address, ptep, entry,
                                                flags & FAULT_FLAG_WRITE))
-               update_mmu_cache(vma, address, entry);
+               update_mmu_cache(vma, address, ptep);
 
 out_page_table_lock:
        spin_unlock(&mm->page_table_lock);
index 09e4b1be7b67ddda8336eee4bd76bbbf304a82b3..72fb5f39bccc32dd17f3aa58f9567f146661301e 100644 (file)
@@ -1593,7 +1593,7 @@ static int insert_pfn(struct vm_area_struct *vma, unsigned long addr,
        /* Ok, finally just insert the thing.. */
        entry = pte_mkspecial(pfn_pte(pfn, prot));
        set_pte_at(mm, addr, pte, entry);
-       update_mmu_cache(vma, addr, entry); /* XXX: why not for insert_page? */
+       update_mmu_cache(vma, addr, pte); /* XXX: why not for insert_page? */
 
        retval = 0;
 out_unlock:
@@ -2116,7 +2116,7 @@ reuse:
                entry = pte_mkyoung(orig_pte);
                entry = maybe_mkwrite(pte_mkdirty(entry), vma);
                if (ptep_set_access_flags(vma, address, page_table, entry,1))
-                       update_mmu_cache(vma, address, entry);
+                       update_mmu_cache(vma, address, page_table);
                ret |= VM_FAULT_WRITE;
                goto unlock;
        }
@@ -2185,7 +2185,7 @@ gotten:
                 * new page to be mapped directly into the secondary page table.
                 */
                set_pte_at_notify(mm, address, page_table, entry);
-               update_mmu_cache(vma, address, entry);
+               update_mmu_cache(vma, address, page_table);
                if (old_page) {
                        /*
                         * Only after switching the pte to the new page may
@@ -2629,7 +2629,7 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
        }
 
        /* No need to invalidate - it was non-present before */
-       update_mmu_cache(vma, address, pte);
+       update_mmu_cache(vma, address, page_table);
 unlock:
        pte_unmap_unlock(page_table, ptl);
 out:
@@ -2694,7 +2694,7 @@ setpte:
        set_pte_at(mm, address, page_table, entry);
 
        /* No need to invalidate - it was non-present before */
-       update_mmu_cache(vma, address, entry);
+       update_mmu_cache(vma, address, page_table);
 unlock:
        pte_unmap_unlock(page_table, ptl);
        return 0;
@@ -2855,7 +2855,7 @@ static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                set_pte_at(mm, address, page_table, entry);
 
                /* no need to invalidate: a not-present page won't be cached */
-               update_mmu_cache(vma, address, entry);
+               update_mmu_cache(vma, address, page_table);
        } else {
                if (charged)
                        mem_cgroup_uncharge_page(page);
@@ -2992,7 +2992,7 @@ static inline int handle_pte_fault(struct mm_struct *mm,
        }
        entry = pte_mkyoung(entry);
        if (ptep_set_access_flags(vma, address, pte, entry, flags & FAULT_FLAG_WRITE)) {
-               update_mmu_cache(vma, address, entry);
+               update_mmu_cache(vma, address, pte);
        } else {
                /*
                 * This is needed only for protection faults but the arch code
index 880bd592d38ea47af36f5f9b64323e8814d09f24..edb6101ed774da0244cb129f332a6914b73465de 100644 (file)
@@ -134,7 +134,7 @@ static int remove_migration_pte(struct page *new, struct vm_area_struct *vma,
                page_add_file_rmap(new);
 
        /* No need to invalidate - it was non-present before */
-       update_mmu_cache(vma, addr, pte);
+       update_mmu_cache(vma, addr, ptep);
 unlock:
        pte_unmap_unlock(ptep, ptl);
 out:
index 268ab7471224a5e42fe4f448df75c7ad4ad7094e..439ce64f9d82edfcfdd867d152dc469969cc1ead 100644 (file)
@@ -237,8 +237,9 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
        access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
                 (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|
                                      SNDRV_CTL_ELEM_ACCESS_INACTIVE|
-                                     SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE|
-                                     SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK));
+                                     SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE|
+                                     SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND|
+                                     SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK));
        kctl.info = ncontrol->info;
        kctl.get = ncontrol->get;
        kctl.put = ncontrol->put;
@@ -1099,7 +1100,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file,
 
        if (copy_from_user(&tlv, _tlv, sizeof(tlv)))
                return -EFAULT;
-       if (tlv.length < sizeof(unsigned int) * 3)
+       if (tlv.length < sizeof(unsigned int) * 2)
                return -EINVAL;
        down_read(&card->controls_rwsem);
        kctl = snd_ctl_find_numid(card, tlv.numid);
index 23a032c6d4873a53b6c95b06ef08f6523332bae4..3da4f92427d8acc129bfba67d2ca29ea0fe56fb1 100644 (file)
@@ -101,8 +101,9 @@ EXPORT_SYMBOL_GPL(__snd_printk);
 #ifdef CONFIG_PCI
 #include <linux/pci.h>
 /**
- * snd_pci_quirk_lookup - look up a PCI SSID quirk list
- * @pci: pci_dev handle
+ * snd_pci_quirk_lookup_id - look up a PCI SSID quirk list
+ * @vendor: PCI SSV id
+ * @device: PCI SSD id
  * @list: quirk list, terminated by a null entry
  *
  * Look through the given quirk list and finds a matching entry
@@ -112,18 +113,39 @@ EXPORT_SYMBOL_GPL(__snd_printk);
  * Returns the matched entry pointer, or NULL if nothing matched.
  */
 const struct snd_pci_quirk *
-snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list)
+snd_pci_quirk_lookup_id(u16 vendor, u16 device,
+                       const struct snd_pci_quirk *list)
 {
        const struct snd_pci_quirk *q;
 
        for (q = list; q->subvendor; q++) {
-               if (q->subvendor != pci->subsystem_vendor)
+               if (q->subvendor != vendor)
                        continue;
                if (!q->subdevice ||
-                   (pci->subsystem_device & q->subdevice_mask) == q->subdevice)
+                   (device & q->subdevice_mask) == q->subdevice)
                        return q;
        }
        return NULL;
 }
+EXPORT_SYMBOL(snd_pci_quirk_lookup_id);
+
+/**
+ * snd_pci_quirk_lookup - look up a PCI SSID quirk list
+ * @pci: pci_dev handle
+ * @list: quirk list, terminated by a null entry
+ *
+ * Look through the given quirk list and finds a matching entry
+ * with the same PCI SSID.  When subdevice is 0, all subdevice
+ * values may match.
+ *
+ * Returns the matched entry pointer, or NULL if nothing matched.
+ */
+const struct snd_pci_quirk *
+snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list)
+{
+       return snd_pci_quirk_lookup_id(pci->subsystem_vendor,
+                                      pci->subsystem_device,
+                                      list);
+}
 EXPORT_SYMBOL(snd_pci_quirk_lookup);
 #endif
index d9c96353121a567b53f040dc1b87207aac40cac4..82d4e3329b3daa11c956e631bab2fb65a59f5d58 100644 (file)
@@ -632,6 +632,12 @@ static long snd_pcm_alsa_frames(struct snd_pcm_substream *substream, long bytes)
        return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes);
 }
 
+static inline
+snd_pcm_uframes_t get_hw_ptr_period(struct snd_pcm_runtime *runtime)
+{
+       return runtime->hw_ptr_interrupt;
+}
+
 /* define extended formats in the recent OSS versions (if any) */
 /* linear formats */
 #define AFMT_S32_LE      0x00001000
@@ -1102,7 +1108,7 @@ static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream)
                return err;
        }
        runtime->oss.prepare = 0;
-       runtime->oss.prev_hw_ptr_interrupt = 0;
+       runtime->oss.prev_hw_ptr_period = 0;
        runtime->oss.period_ptr = 0;
        runtime->oss.buffer_used = 0;
 
@@ -1950,7 +1956,8 @@ static int snd_pcm_oss_get_caps(struct snd_pcm_oss_file *pcm_oss_file)
        return result;
 }
 
-static void snd_pcm_oss_simulate_fill(struct snd_pcm_substream *substream, snd_pcm_uframes_t hw_ptr)
+static void snd_pcm_oss_simulate_fill(struct snd_pcm_substream *substream,
+                                     snd_pcm_uframes_t hw_ptr)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        snd_pcm_uframes_t appl_ptr;
@@ -1986,7 +1993,8 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr
                        if (runtime->oss.trigger)
                                goto _skip1;
                        if (atomic_read(&psubstream->mmap_count))
-                               snd_pcm_oss_simulate_fill(psubstream, runtime->hw_ptr_interrupt);
+                               snd_pcm_oss_simulate_fill(psubstream,
+                                               get_hw_ptr_period(runtime));
                        runtime->oss.trigger = 1;
                        runtime->start_threshold = 1;
                        cmd = SNDRV_PCM_IOCTL_START;
@@ -2105,11 +2113,12 @@ static int snd_pcm_oss_get_ptr(struct snd_pcm_oss_file *pcm_oss_file, int stream
        info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size);
        if (atomic_read(&substream->mmap_count)) {
                snd_pcm_sframes_t n;
-               n = (delay = runtime->hw_ptr_interrupt) - runtime->oss.prev_hw_ptr_interrupt;
+               delay = get_hw_ptr_period(runtime);
+               n = delay - runtime->oss.prev_hw_ptr_period;
                if (n < 0)
                        n += runtime->boundary;
                info.blocks = n / runtime->period_size;
-               runtime->oss.prev_hw_ptr_interrupt = delay;
+               runtime->oss.prev_hw_ptr_period = delay;
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                        snd_pcm_oss_simulate_fill(substream, delay);
                info.bytes = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr) & INT_MAX;
@@ -2673,18 +2682,22 @@ static int snd_pcm_oss_playback_ready(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        if (atomic_read(&substream->mmap_count))
-               return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt;
+               return runtime->oss.prev_hw_ptr_period !=
+                                               get_hw_ptr_period(runtime);
        else
-               return snd_pcm_playback_avail(runtime) >= runtime->oss.period_frames;
+               return snd_pcm_playback_avail(runtime) >=
+                                               runtime->oss.period_frames;
 }
 
 static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        if (atomic_read(&substream->mmap_count))
-               return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt;
+               return runtime->oss.prev_hw_ptr_period !=
+                                               get_hw_ptr_period(runtime);
        else
-               return snd_pcm_capture_avail(runtime) >= runtime->oss.period_frames;
+               return snd_pcm_capture_avail(runtime) >=
+                                               runtime->oss.period_frames;
 }
 
 static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait)
index 6884ae031f6fc4975c52fb4beb026aeaa61f2248..0d428d0896dbd564520f33f28f797912906b2c58 100644 (file)
@@ -894,6 +894,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
        memset((void*)runtime->control, 0, size);
 
        init_waitqueue_head(&runtime->sleep);
+       init_waitqueue_head(&runtime->tsleep);
 
        runtime->status->state = SNDRV_PCM_STATE_OPEN;
 
@@ -921,6 +922,10 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
        snd_free_pages((void*)runtime->control,
                       PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)));
        kfree(runtime->hw_constraints.rules);
+#ifdef CONFIG_SND_PCM_XRUN_DEBUG
+       if (runtime->hwptr_log)
+               kfree(runtime->hwptr_log);
+#endif
        kfree(runtime);
        substream->runtime = NULL;
        put_pid(substream->pid);
index a27545b23ee9ff031e8eb98346a492516db42b8b..b546ac2660f9f64b8436e3efe836cfa0f298afee 100644 (file)
@@ -126,17 +126,6 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
        }
 }
 
-#ifdef CONFIG_SND_PCM_XRUN_DEBUG
-#define xrun_debug(substream, mask)    ((substream)->pstr->xrun_debug & (mask))
-#else
-#define xrun_debug(substream, mask)    0
-#endif
-
-#define dump_stack_on_xrun(substream) do {             \
-               if (xrun_debug(substream, 2))           \
-                       dump_stack();                   \
-       } while (0)
-
 static void pcm_debug_name(struct snd_pcm_substream *substream,
                           char *name, size_t len)
 {
@@ -147,6 +136,24 @@ static void pcm_debug_name(struct snd_pcm_substream *substream,
                 substream->number);
 }
 
+#define XRUN_DEBUG_BASIC       (1<<0)
+#define XRUN_DEBUG_STACK       (1<<1)  /* dump also stack */
+#define XRUN_DEBUG_JIFFIESCHECK        (1<<2)  /* do jiffies check */
+#define XRUN_DEBUG_PERIODUPDATE        (1<<3)  /* full period update info */
+#define XRUN_DEBUG_HWPTRUPDATE (1<<4)  /* full hwptr update info */
+#define XRUN_DEBUG_LOG         (1<<5)  /* show last 10 positions on err */
+#define XRUN_DEBUG_LOGONCE     (1<<6)  /* do above only once */
+
+#ifdef CONFIG_SND_PCM_XRUN_DEBUG
+
+#define xrun_debug(substream, mask) \
+                       ((substream)->pstr->xrun_debug & (mask))
+
+#define dump_stack_on_xrun(substream) do {                     \
+               if (xrun_debug(substream, XRUN_DEBUG_STACK))    \
+                       dump_stack();                           \
+       } while (0)
+
 static void xrun(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
@@ -154,7 +161,7 @@ static void xrun(struct snd_pcm_substream *substream)
        if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
                snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
        snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
-       if (xrun_debug(substream, 1)) {
+       if (xrun_debug(substream, XRUN_DEBUG_BASIC)) {
                char name[16];
                pcm_debug_name(substream, name, sizeof(name));
                snd_printd(KERN_DEBUG "XRUN: %s\n", name);
@@ -162,32 +169,102 @@ static void xrun(struct snd_pcm_substream *substream)
        }
 }
 
-static snd_pcm_uframes_t
-snd_pcm_update_hw_ptr_pos(struct snd_pcm_substream *substream,
-                         struct snd_pcm_runtime *runtime)
-{
+#define hw_ptr_error(substream, fmt, args...)                          \
+       do {                                                            \
+               if (xrun_debug(substream, XRUN_DEBUG_BASIC)) {          \
+                       xrun_log_show(substream);                       \
+                       if (printk_ratelimit()) {                       \
+                               snd_printd("PCM: " fmt, ##args);        \
+                       }                                               \
+                       dump_stack_on_xrun(substream);                  \
+               }                                                       \
+       } while (0)
+
+#define XRUN_LOG_CNT   10
+
+struct hwptr_log_entry {
+       unsigned long jiffies;
        snd_pcm_uframes_t pos;
+       snd_pcm_uframes_t period_size;
+       snd_pcm_uframes_t buffer_size;
+       snd_pcm_uframes_t old_hw_ptr;
+       snd_pcm_uframes_t hw_ptr_base;
+};
 
-       pos = substream->ops->pointer(substream);
-       if (pos == SNDRV_PCM_POS_XRUN)
-               return pos; /* XRUN */
-       if (pos >= runtime->buffer_size) {
-               if (printk_ratelimit()) {
-                       char name[16];
-                       pcm_debug_name(substream, name, sizeof(name));
-                       snd_printd(KERN_ERR  "BUG: %s, pos = 0x%lx, "
-                                  "buffer size = 0x%lx, period size = 0x%lx\n",
-                                  name, pos, runtime->buffer_size,
-                                  runtime->period_size);
-               }
-               pos = 0;
+struct snd_pcm_hwptr_log {
+       unsigned int idx;
+       unsigned int hit: 1;
+       struct hwptr_log_entry entries[XRUN_LOG_CNT];
+};
+
+static void xrun_log(struct snd_pcm_substream *substream,
+                    snd_pcm_uframes_t pos)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_pcm_hwptr_log *log = runtime->hwptr_log;
+       struct hwptr_log_entry *entry;
+
+       if (log == NULL) {
+               log = kzalloc(sizeof(*log), GFP_ATOMIC);
+               if (log == NULL)
+                       return;
+               runtime->hwptr_log = log;
+       } else {
+               if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit)
+                       return;
        }
-       pos -= pos % runtime->min_align;
-       return pos;
+       entry = &log->entries[log->idx];
+       entry->jiffies = jiffies;
+       entry->pos = pos;
+       entry->period_size = runtime->period_size;
+       entry->buffer_size = runtime->buffer_size;;
+       entry->old_hw_ptr = runtime->status->hw_ptr;
+       entry->hw_ptr_base = runtime->hw_ptr_base;
+       log->idx = (log->idx + 1) % XRUN_LOG_CNT;
+}
+
+static void xrun_log_show(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_hwptr_log *log = substream->runtime->hwptr_log;
+       struct hwptr_log_entry *entry;
+       char name[16];
+       unsigned int idx;
+       int cnt;
+
+       if (log == NULL)
+               return;
+       if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit)
+               return;
+       pcm_debug_name(substream, name, sizeof(name));
+       for (cnt = 0, idx = log->idx; cnt < XRUN_LOG_CNT; cnt++) {
+               entry = &log->entries[idx];
+               if (entry->period_size == 0)
+                       break;
+               snd_printd("hwptr log: %s: j=%lu, pos=%ld/%ld/%ld, "
+                          "hwptr=%ld/%ld\n",
+                          name, entry->jiffies, (unsigned long)entry->pos,
+                          (unsigned long)entry->period_size,
+                          (unsigned long)entry->buffer_size,
+                          (unsigned long)entry->old_hw_ptr,
+                          (unsigned long)entry->hw_ptr_base);
+               idx++;
+               idx %= XRUN_LOG_CNT;
+       }
+       log->hit = 1;
 }
 
-static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream,
-                                     struct snd_pcm_runtime *runtime)
+#else /* ! CONFIG_SND_PCM_XRUN_DEBUG */
+
+#define xrun_debug(substream, mask)    0
+#define xrun(substream)                        do { } while (0)
+#define hw_ptr_error(substream, fmt, args...) do { } while (0)
+#define xrun_log(substream, pos)       do { } while (0)
+#define xrun_log_show(substream)       do { } while (0)
+
+#endif
+
+int snd_pcm_update_state(struct snd_pcm_substream *substream,
+                        struct snd_pcm_runtime *runtime)
 {
        snd_pcm_uframes_t avail;
 
@@ -209,88 +286,94 @@ static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream,
                }
        }
        if (avail >= runtime->control->avail_min)
-               wake_up(&runtime->sleep);
+               wake_up(runtime->twake ? &runtime->tsleep : &runtime->sleep);
        return 0;
 }
 
-#define hw_ptr_error(substream, fmt, args...)                          \
-       do {                                                            \
-               if (xrun_debug(substream, 1)) {                         \
-                       if (printk_ratelimit()) {                       \
-                               snd_printd("PCM: " fmt, ##args);        \
-                       }                                               \
-                       dump_stack_on_xrun(substream);                  \
-               }                                                       \
-       } while (0)
-
-static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
+static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
+                                 unsigned int in_interrupt)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        snd_pcm_uframes_t pos;
-       snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_ptr_interrupt, hw_base;
+       snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base;
        snd_pcm_sframes_t hdelta, delta;
        unsigned long jdelta;
 
        old_hw_ptr = runtime->status->hw_ptr;
-       pos = snd_pcm_update_hw_ptr_pos(substream, runtime);
+       pos = substream->ops->pointer(substream);
        if (pos == SNDRV_PCM_POS_XRUN) {
                xrun(substream);
                return -EPIPE;
        }
-       if (xrun_debug(substream, 8)) {
-               char name[16];
-               pcm_debug_name(substream, name, sizeof(name));
-               snd_printd("period_update: %s: pos=0x%x/0x%x/0x%x, "
-                          "hwptr=0x%lx, hw_base=0x%lx, hw_intr=0x%lx\n",
-                          name, (unsigned int)pos,
-                          (unsigned int)runtime->period_size,
-                          (unsigned int)runtime->buffer_size,
-                          (unsigned long)old_hw_ptr,
-                          (unsigned long)runtime->hw_ptr_base,
-                          (unsigned long)runtime->hw_ptr_interrupt);
+       if (pos >= runtime->buffer_size) {
+               if (printk_ratelimit()) {
+                       char name[16];
+                       pcm_debug_name(substream, name, sizeof(name));
+                       xrun_log_show(substream);
+                       snd_printd(KERN_ERR  "BUG: %s, pos = %ld, "
+                                  "buffer size = %ld, period size = %ld\n",
+                                  name, pos, runtime->buffer_size,
+                                  runtime->period_size);
+               }
+               pos = 0;
        }
+       pos -= pos % runtime->min_align;
+       if (xrun_debug(substream, XRUN_DEBUG_LOG))
+               xrun_log(substream, pos);
        hw_base = runtime->hw_ptr_base;
        new_hw_ptr = hw_base + pos;
-       hw_ptr_interrupt = runtime->hw_ptr_interrupt + runtime->period_size;
-       delta = new_hw_ptr - hw_ptr_interrupt;
-       if (hw_ptr_interrupt >= runtime->boundary) {
-               hw_ptr_interrupt -= runtime->boundary;
-               if (hw_base < runtime->boundary / 2)
-                       /* hw_base was already lapped; recalc delta */
-                       delta = new_hw_ptr - hw_ptr_interrupt;
-       }
-       if (delta < 0) {
-               if (runtime->periods == 1 || new_hw_ptr < old_hw_ptr)
-                       delta += runtime->buffer_size;
-               if (delta < 0) {
-                       hw_ptr_error(substream, 
-                                    "Unexpected hw_pointer value "
-                                    "(stream=%i, pos=%ld, intr_ptr=%ld)\n",
-                                    substream->stream, (long)pos,
-                                    (long)hw_ptr_interrupt);
-#if 1
-                       /* simply skipping the hwptr update seems more
-                        * robust in some cases, e.g. on VMware with
-                        * inaccurate timer source
-                        */
-                       return 0; /* skip this update */
-#else
-                       /* rebase to interrupt position */
-                       hw_base = new_hw_ptr = hw_ptr_interrupt;
-                       /* align hw_base to buffer_size */
-                       hw_base -= hw_base % runtime->buffer_size;
-                       delta = 0;
-#endif
-               } else {
+       if (in_interrupt) {
+               /* we know that one period was processed */
+               /* 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;
                }
        }
+       /* new_hw_ptr might be lower than old_hw_ptr in case when */
+       /* pointer crosses the end of the ring buffer */
+       if (new_hw_ptr < old_hw_ptr) {
+               hw_base += runtime->buffer_size;
+               if (hw_base >= runtime->boundary)
+                       hw_base = 0;
+               new_hw_ptr = hw_base + pos;
+       }
+      __delta:
+       delta = (new_hw_ptr - old_hw_ptr) % runtime->boundary;
+       if (xrun_debug(substream, in_interrupt ?
+                       XRUN_DEBUG_PERIODUPDATE : XRUN_DEBUG_HWPTRUPDATE)) {
+               char name[16];
+               pcm_debug_name(substream, name, sizeof(name));
+               snd_printd("%s_update: %s: pos=%u/%u/%u, "
+                          "hwptr=%ld/%ld/%ld/%ld\n",
+                          in_interrupt ? "period" : "hwptr",
+                          name,
+                          (unsigned int)pos,
+                          (unsigned int)runtime->period_size,
+                          (unsigned int)runtime->buffer_size,
+                          (unsigned long)delta,
+                          (unsigned long)old_hw_ptr,
+                          (unsigned long)new_hw_ptr,
+                          (unsigned long)runtime->hw_ptr_base);
+       }
+       /* something must be really wrong */
+       if (delta >= runtime->buffer_size + runtime->period_size) {
+               hw_ptr_error(substream,
+                              "Unexpected hw_pointer value %s"
+                              "(stream=%i, pos=%ld, new_hw_ptr=%ld, "
+                              "old_hw_ptr=%ld)\n",
+                                    in_interrupt ? "[Q] " : "[P]",
+                                    substream->stream, (long)pos,
+                                    (long)new_hw_ptr, (long)old_hw_ptr);
+               return 0;
+       }
 
        /* Do jiffies check only in xrun_debug mode */
-       if (!xrun_debug(substream, 4))
+       if (!xrun_debug(substream, XRUN_DEBUG_JIFFIESCHECK))
                goto no_jiffies_check;
 
        /* Skip the jiffies check for hardwares with BATCH flag.
@@ -299,7 +382,7 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
         */
        if (runtime->hw.info & SNDRV_PCM_INFO_BATCH)
                goto no_jiffies_check;
-       hdelta = new_hw_ptr - old_hw_ptr;
+       hdelta = delta;
        if (hdelta < runtime->delay)
                goto no_jiffies_check;
        hdelta -= runtime->delay;
@@ -308,130 +391,68 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
                delta = jdelta /
                        (((runtime->period_size * HZ) / runtime->rate)
                                                                + HZ/100);
+               /* move new_hw_ptr according jiffies not pos variable */
+               new_hw_ptr = old_hw_ptr;
+               hw_base = delta;
+               /* use loop to avoid checks for delta overflows */
+               /* the delta value is small or zero in most cases */
+               while (delta > 0) {
+                       new_hw_ptr += runtime->period_size;
+                       if (new_hw_ptr >= runtime->boundary)
+                               new_hw_ptr -= runtime->boundary;
+                       delta--;
+               }
+               /* align hw_base to buffer_size */
                hw_ptr_error(substream,
-                            "hw_ptr skipping! [Q] "
+                            "hw_ptr skipping! %s"
                             "(pos=%ld, delta=%ld, period=%ld, "
-                            "jdelta=%lu/%lu/%lu)\n",
+                            "jdelta=%lu/%lu/%lu, hw_ptr=%ld/%ld)\n",
+                            in_interrupt ? "[Q] " : "",
                             (long)pos, (long)hdelta,
                             (long)runtime->period_size, jdelta,
-                            ((hdelta * HZ) / runtime->rate), delta);
-               hw_ptr_interrupt = runtime->hw_ptr_interrupt +
-                                  runtime->period_size * delta;
-               if (hw_ptr_interrupt >= runtime->boundary)
-                       hw_ptr_interrupt -= runtime->boundary;
-               /* rebase to interrupt position */
-               hw_base = new_hw_ptr = hw_ptr_interrupt;
-               /* align hw_base to buffer_size */
-               hw_base -= hw_base % runtime->buffer_size;
+                            ((hdelta * HZ) / runtime->rate), hw_base,
+                            (unsigned long)old_hw_ptr,
+                            (unsigned long)new_hw_ptr);
+               /* reset values to proper state */
                delta = 0;
+               hw_base = new_hw_ptr - (new_hw_ptr % runtime->buffer_size);
        }
  no_jiffies_check:
        if (delta > runtime->period_size + runtime->period_size / 2) {
                hw_ptr_error(substream,
-                            "Lost interrupts? "
-                            "(stream=%i, delta=%ld, intr_ptr=%ld)\n",
+                            "Lost interrupts? %s"
+                            "(stream=%i, delta=%ld, new_hw_ptr=%ld, "
+                            "old_hw_ptr=%ld)\n",
+                            in_interrupt ? "[Q] " : "",
                             substream->stream, (long)delta,
-                            (long)hw_ptr_interrupt);
-               /* rebase hw_ptr_interrupt */
-               hw_ptr_interrupt =
-                       new_hw_ptr - new_hw_ptr % runtime->period_size;
+                            (long)new_hw_ptr,
+                            (long)old_hw_ptr);
        }
-       runtime->hw_ptr_interrupt = hw_ptr_interrupt;
+
+       if (runtime->status->hw_ptr == new_hw_ptr)
+               return 0;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
            runtime->silence_size > 0)
                snd_pcm_playback_silence(substream, new_hw_ptr);
 
-       if (runtime->status->hw_ptr == new_hw_ptr)
-               return 0;
-
+       if (in_interrupt) {
+               runtime->hw_ptr_interrupt = new_hw_ptr -
+                               (new_hw_ptr % runtime->period_size);
+       }
        runtime->hw_ptr_base = hw_base;
        runtime->status->hw_ptr = new_hw_ptr;
        runtime->hw_ptr_jiffies = jiffies;
        if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
                snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
 
-       return snd_pcm_update_hw_ptr_post(substream, runtime);
+       return snd_pcm_update_state(substream, runtime);
 }
 
 /* CAUTION: call it with irq disabled */
 int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
 {
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       snd_pcm_uframes_t pos;
-       snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base;
-       snd_pcm_sframes_t delta;
-       unsigned long jdelta;
-
-       old_hw_ptr = runtime->status->hw_ptr;
-       pos = snd_pcm_update_hw_ptr_pos(substream, runtime);
-       if (pos == SNDRV_PCM_POS_XRUN) {
-               xrun(substream);
-               return -EPIPE;
-       }
-       if (xrun_debug(substream, 16)) {
-               char name[16];
-               pcm_debug_name(substream, name, sizeof(name));
-               snd_printd("hw_update: %s: pos=0x%x/0x%x/0x%x, "
-                          "hwptr=0x%lx, hw_base=0x%lx, hw_intr=0x%lx\n",
-                          name, (unsigned int)pos,
-                          (unsigned int)runtime->period_size,
-                          (unsigned int)runtime->buffer_size,
-                          (unsigned long)old_hw_ptr,
-                          (unsigned long)runtime->hw_ptr_base,
-                          (unsigned long)runtime->hw_ptr_interrupt);
-       }
-
-       hw_base = runtime->hw_ptr_base;
-       new_hw_ptr = hw_base + pos;
-
-       delta = new_hw_ptr - old_hw_ptr;
-       jdelta = jiffies - runtime->hw_ptr_jiffies;
-       if (delta < 0) {
-               delta += runtime->buffer_size;
-               if (delta < 0) {
-                       hw_ptr_error(substream, 
-                                    "Unexpected hw_pointer value [2] "
-                                    "(stream=%i, pos=%ld, old_ptr=%ld, jdelta=%li)\n",
-                                    substream->stream, (long)pos,
-                                    (long)old_hw_ptr, jdelta);
-                       return 0;
-               }
-               hw_base += runtime->buffer_size;
-               if (hw_base >= runtime->boundary)
-                       hw_base = 0;
-               new_hw_ptr = hw_base + pos;
-       }
-       /* Do jiffies check only in xrun_debug mode */
-       if (!xrun_debug(substream, 4))
-               goto no_jiffies_check;
-       if (delta < runtime->delay)
-               goto no_jiffies_check;
-       delta -= runtime->delay;
-       if (((delta * HZ) / runtime->rate) > jdelta + HZ/100) {
-               hw_ptr_error(substream,
-                            "hw_ptr skipping! "
-                            "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu)\n",
-                            (long)pos, (long)delta,
-                            (long)runtime->period_size, jdelta,
-                            ((delta * HZ) / runtime->rate));
-               return 0;
-       }
- no_jiffies_check:
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
-           runtime->silence_size > 0)
-               snd_pcm_playback_silence(substream, new_hw_ptr);
-
-       if (runtime->status->hw_ptr == new_hw_ptr)
-               return 0;
-
-       runtime->hw_ptr_base = hw_base;
-       runtime->status->hw_ptr = new_hw_ptr;
-       runtime->hw_ptr_jiffies = jiffies;
-       if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
-               snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
-
-       return snd_pcm_update_hw_ptr_post(substream, runtime);
+       return snd_pcm_update_hw_ptr0(substream, 0);
 }
 
 /**
@@ -745,10 +766,13 @@ int snd_interval_ratnum(struct snd_interval *i,
                        unsigned int rats_count, struct snd_ratnum *rats,
                        unsigned int *nump, unsigned int *denp)
 {
-       unsigned int best_num, best_diff, best_den;
+       unsigned int best_num, best_den;
+       int best_diff;
        unsigned int k;
        struct snd_interval t;
        int err;
+       unsigned int result_num, result_den;
+       int result_diff;
 
        best_num = best_den = best_diff = 0;
        for (k = 0; k < rats_count; ++k) {
@@ -770,6 +794,8 @@ int snd_interval_ratnum(struct snd_interval *i,
                                den -= r;
                }
                diff = num - q * den;
+               if (diff < 0)
+                       diff = -diff;
                if (best_num == 0 ||
                    diff * best_den < best_diff * den) {
                        best_diff = diff;
@@ -784,6 +810,9 @@ int snd_interval_ratnum(struct snd_interval *i,
        t.min = div_down(best_num, best_den);
        t.openmin = !!(best_num % best_den);
        
+       result_num = best_num;
+       result_diff = best_diff;
+       result_den = best_den;
        best_num = best_den = best_diff = 0;
        for (k = 0; k < rats_count; ++k) {
                unsigned int num = rats[k].num;
@@ -806,6 +835,8 @@ int snd_interval_ratnum(struct snd_interval *i,
                                den += rats[k].den_step - r;
                }
                diff = q * den - num;
+               if (diff < 0)
+                       diff = -diff;
                if (best_num == 0 ||
                    diff * best_den < best_diff * den) {
                        best_diff = diff;
@@ -825,10 +856,14 @@ int snd_interval_ratnum(struct snd_interval *i,
                return err;
 
        if (snd_interval_single(i)) {
+               if (best_diff * result_den < result_diff * best_den) {
+                       result_num = best_num;
+                       result_den = best_den;
+               }
                if (nump)
-                       *nump = best_num;
+                       *nump = result_num;
                if (denp)
-                       *denp = best_den;
+                       *denp = result_den;
        }
        return err;
 }
@@ -1643,7 +1678,7 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
 
        snd_pcm_stream_lock_irqsave(substream, flags);
        if (!snd_pcm_running(substream) ||
-           snd_pcm_update_hw_ptr_interrupt(substream) < 0)
+           snd_pcm_update_hw_ptr0(substream, 1) < 0)
                goto _end;
 
        if (substream->timer_running)
@@ -1674,7 +1709,7 @@ static int wait_for_avail_min(struct snd_pcm_substream *substream,
        long tout;
 
        init_waitqueue_entry(&wait, current);
-       add_wait_queue(&runtime->sleep, &wait);
+       add_wait_queue(&runtime->tsleep, &wait);
        for (;;) {
                if (signal_pending(current)) {
                        err = -ERESTARTSYS;
@@ -1717,7 +1752,7 @@ static int wait_for_avail_min(struct snd_pcm_substream *substream,
                        break;
        }
  _endloop:
-       remove_wait_queue(&runtime->sleep, &wait);
+       remove_wait_queue(&runtime->tsleep, &wait);
        *availp = avail;
        return err;
 }
@@ -1776,6 +1811,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
                goto _end_unlock;
        }
 
+       runtime->twake = 1;
        while (size > 0) {
                snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
                snd_pcm_uframes_t avail;
@@ -1797,15 +1833,17 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
                if (frames > cont)
                        frames = cont;
                if (snd_BUG_ON(!frames)) {
+                       runtime->twake = 0;
                        snd_pcm_stream_unlock_irq(substream);
                        return -EINVAL;
                }
                appl_ptr = runtime->control->appl_ptr;
                appl_ofs = appl_ptr % runtime->buffer_size;
                snd_pcm_stream_unlock_irq(substream);
-               if ((err = transfer(substream, appl_ofs, data, offset, frames)) < 0)
-                       goto _end;
+               err = transfer(substream, appl_ofs, data, offset, frames);
                snd_pcm_stream_lock_irq(substream);
+               if (err < 0)
+                       goto _end_unlock;
                switch (runtime->status->state) {
                case SNDRV_PCM_STATE_XRUN:
                        err = -EPIPE;
@@ -1834,8 +1872,10 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
                }
        }
  _end_unlock:
+       runtime->twake = 0;
+       if (xfer > 0 && err >= 0)
+               snd_pcm_update_state(substream, runtime);
        snd_pcm_stream_unlock_irq(substream);
- _end:
        return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
 }
 
@@ -1993,6 +2033,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
                goto _end_unlock;
        }
 
+       runtime->twake = 1;
        while (size > 0) {
                snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
                snd_pcm_uframes_t avail;
@@ -2021,15 +2062,17 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
                if (frames > cont)
                        frames = cont;
                if (snd_BUG_ON(!frames)) {
+                       runtime->twake = 0;
                        snd_pcm_stream_unlock_irq(substream);
                        return -EINVAL;
                }
                appl_ptr = runtime->control->appl_ptr;
                appl_ofs = appl_ptr % runtime->buffer_size;
                snd_pcm_stream_unlock_irq(substream);
-               if ((err = transfer(substream, appl_ofs, data, offset, frames)) < 0)
-                       goto _end;
+               err = transfer(substream, appl_ofs, data, offset, frames);
                snd_pcm_stream_lock_irq(substream);
+               if (err < 0)
+                       goto _end_unlock;
                switch (runtime->status->state) {
                case SNDRV_PCM_STATE_XRUN:
                        err = -EPIPE;
@@ -2052,8 +2095,10 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
                xfer += frames;
        }
  _end_unlock:
+       runtime->twake = 0;
+       if (xfer > 0 && err >= 0)
+               snd_pcm_update_state(substream, runtime);
        snd_pcm_stream_unlock_irq(substream);
- _end:
        return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
 }
 
index caa7796bc2f513e2bb2a73c1c26a8c866856894b..d6d49d6651f9122a389572db10d4f2ff078bbec2 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/time.h>
 #include <linux/init.h>
 #include <linux/moduleparam.h>
+#include <linux/vmalloc.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/info.h>
@@ -434,3 +435,57 @@ int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream)
 }
 
 EXPORT_SYMBOL(snd_pcm_lib_free_pages);
+
+int _snd_pcm_lib_alloc_vmalloc_buffer(struct snd_pcm_substream *substream,
+                                     size_t size, gfp_t gfp_flags)
+{
+       struct snd_pcm_runtime *runtime;
+
+       if (PCM_RUNTIME_CHECK(substream))
+               return -EINVAL;
+       runtime = substream->runtime;
+       if (runtime->dma_area) {
+               if (runtime->dma_bytes >= size)
+                       return 0; /* already large enough */
+               vfree(runtime->dma_area);
+       }
+       runtime->dma_area = __vmalloc(size, gfp_flags, PAGE_KERNEL);
+       if (!runtime->dma_area)
+               return -ENOMEM;
+       runtime->dma_bytes = size;
+       return 1;
+}
+EXPORT_SYMBOL(_snd_pcm_lib_alloc_vmalloc_buffer);
+
+/**
+ * snd_pcm_lib_free_vmalloc_buffer - free vmalloc buffer
+ * @substream: the substream with a buffer allocated by
+ *     snd_pcm_lib_alloc_vmalloc_buffer()
+ */
+int snd_pcm_lib_free_vmalloc_buffer(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime;
+
+       if (PCM_RUNTIME_CHECK(substream))
+               return -EINVAL;
+       runtime = substream->runtime;
+       vfree(runtime->dma_area);
+       runtime->dma_area = NULL;
+       return 0;
+}
+EXPORT_SYMBOL(snd_pcm_lib_free_vmalloc_buffer);
+
+/**
+ * snd_pcm_lib_get_vmalloc_page - map vmalloc buffer offset to page struct
+ * @substream: the substream with a buffer allocated by
+ *     snd_pcm_lib_alloc_vmalloc_buffer()
+ * @offset: offset in the buffer
+ *
+ * This function is to be used as the page callback in the PCM ops.
+ */
+struct page *snd_pcm_lib_get_vmalloc_page(struct snd_pcm_substream *substream,
+                                         unsigned long offset)
+{
+       return vmalloc_to_page(substream->runtime->dma_area + offset);
+}
+EXPORT_SYMBOL(snd_pcm_lib_get_vmalloc_page);
index 25b0641e6b8c28b7afefb3e54648990f6618e80c..87288762403055a3f6f842c70b9e99794956a1cd 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/pm_qos_params.h>
 #include <linux/uio.h>
 #include <linux/dma-mapping.h>
+#include <linux/math64.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/info.h>
@@ -315,10 +316,10 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
        if (!params->info)
                params->info = hw->info & ~SNDRV_PCM_INFO_FIFO_IN_FRAMES;
        if (!params->fifo_size) {
-               if (snd_mask_min(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT]) ==
-                   snd_mask_max(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT]) &&
-                    snd_mask_min(&params->masks[SNDRV_PCM_HW_PARAM_CHANNELS]) ==
-                    snd_mask_max(&params->masks[SNDRV_PCM_HW_PARAM_CHANNELS])) {
+               m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+               i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+               if (snd_mask_min(m) == snd_mask_max(m) &&
+                    snd_interval_min(i) == snd_interval_max(i)) {
                        changed = substream->ops->ioctl(substream,
                                        SNDRV_PCM_IOCTL1_FIFO_SIZE, params);
                        if (changed < 0)
@@ -366,6 +367,38 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime)
        return usecs;
 }
 
+static int calc_boundary(struct snd_pcm_runtime *runtime)
+{
+       u_int64_t boundary;
+
+       boundary = (u_int64_t)runtime->buffer_size *
+                  (u_int64_t)runtime->period_size;
+#if BITS_PER_LONG < 64
+       /* try to find lowest common multiple for buffer and period */
+       if (boundary > LONG_MAX - runtime->buffer_size) {
+               u_int32_t remainder = -1;
+               u_int32_t divident = runtime->buffer_size;
+               u_int32_t divisor = runtime->period_size;
+               while (remainder) {
+                       remainder = divident % divisor;
+                       if (remainder) {
+                               divident = divisor;
+                               divisor = remainder;
+                       }
+               }
+               boundary = div_u64(boundary, divisor);
+               if (boundary > LONG_MAX - runtime->buffer_size)
+                       return -ERANGE;
+       }
+#endif
+       if (boundary == 0)
+               return -ERANGE;
+       runtime->boundary = boundary;
+       while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size)
+               runtime->boundary *= 2;
+       return 0;
+}
+
 static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
                             struct snd_pcm_hw_params *params)
 {
@@ -441,9 +474,9 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
        runtime->stop_threshold = runtime->buffer_size;
        runtime->silence_threshold = 0;
        runtime->silence_size = 0;
-       runtime->boundary = runtime->buffer_size;
-       while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size)
-               runtime->boundary *= 2;
+       err = calc_boundary(runtime);
+       if (err < 0)
+               goto _error;
 
        snd_pcm_timer_resolution_change(substream);
        runtime->status->state = SNDRV_PCM_STATE_SETUP;
@@ -516,6 +549,7 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
                             struct snd_pcm_sw_params *params)
 {
        struct snd_pcm_runtime *runtime;
+       int err;
 
        if (PCM_RUNTIME_CHECK(substream))
                return -ENXIO;
@@ -540,6 +574,7 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
                if (params->silence_threshold > runtime->buffer_size)
                        return -EINVAL;
        }
+       err = 0;
        snd_pcm_stream_lock_irq(substream);
        runtime->tstamp_mode = params->tstamp_mode;
        runtime->period_step = params->period_step;
@@ -553,10 +588,10 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
                    runtime->silence_size > 0)
                        snd_pcm_playback_silence(substream, ULONG_MAX);
-               wake_up(&runtime->sleep);
+               err = snd_pcm_update_state(substream, runtime);
        }
        snd_pcm_stream_unlock_irq(substream);
-       return 0;
+       return err;
 }
 
 static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream,
@@ -917,6 +952,7 @@ static void snd_pcm_post_stop(struct snd_pcm_substream *substream, int state)
                runtime->status->state = state;
        }
        wake_up(&runtime->sleep);
+       wake_up(&runtime->tsleep);
 }
 
 static struct action_ops snd_pcm_action_stop = {
@@ -1002,6 +1038,7 @@ static void snd_pcm_post_pause(struct snd_pcm_substream *substream, int push)
                                         SNDRV_TIMER_EVENT_MPAUSE,
                                         &runtime->trigger_tstamp);
                wake_up(&runtime->sleep);
+               wake_up(&runtime->tsleep);
        } else {
                runtime->status->state = SNDRV_PCM_STATE_RUNNING;
                if (substream->timer)
@@ -1059,6 +1096,7 @@ static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state)
        runtime->status->suspended_state = runtime->status->state;
        runtime->status->state = SNDRV_PCM_STATE_SUSPENDED;
        wake_up(&runtime->sleep);
+       wake_up(&runtime->tsleep);
 }
 
 static struct action_ops snd_pcm_action_suspend = {
@@ -3162,9 +3200,7 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
        long size;
        unsigned long offset;
 
-#ifdef pgprot_noncached
        area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
-#endif
        area->vm_flags |= VM_IO;
        size = area->vm_end - area->vm_start;
        offset = area->vm_pgoff << PAGE_SHIFT;
@@ -3178,6 +3214,15 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
 EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem);
 #endif /* SNDRV_PCM_INFO_MMAP */
 
+/* mmap callback with pgprot_noncached */
+int snd_pcm_lib_mmap_noncached(struct snd_pcm_substream *substream,
+                              struct vm_area_struct *area)
+{
+       area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
+       return snd_pcm_default_mmap(substream, area);
+}
+EXPORT_SYMBOL(snd_pcm_lib_mmap_noncached);
+
 /*
  * mmap DMA buffer
  */
index 8ca2be339f3bacb230c584472f5a371f6098073b..48eca9ff9ee7e144d2dac18f17e2c6b2f817f286 100644 (file)
@@ -2190,7 +2190,7 @@ static int snd_seq_do_ioctl(struct snd_seq_client *client, unsigned int cmd,
                if (p->cmd == cmd)
                        return p->func(client, arg);
        }
-       snd_printd("seq unknown ioctl() 0x%x (type='%c', number=0x%2x)\n",
+       snd_printd("seq unknown ioctl() 0x%x (type='%c', number=0x%02x)\n",
                   cmd, _IOC_TYPE(cmd), _IOC_NR(cmd));
        return -ENOTTY;
 }
index f745c317d6af17e9acb98928eb1332541299b8ec..160b1bd0cd62262931896573953e990736e4da52 100644 (file)
 
 #define SKEW_BASE      0x10000 /* 16bit shift */
 
-static void snd_seq_timer_set_tick_resolution(struct snd_seq_timer_tick *tick,
-                                             int tempo, int ppq)
+static void snd_seq_timer_set_tick_resolution(struct snd_seq_timer *tmr)
 {
-       if (tempo < 1000000)
-               tick->resolution = (tempo * 1000) / ppq;
+       if (tmr->tempo < 1000000)
+               tmr->tick.resolution = (tmr->tempo * 1000) / tmr->ppq;
        else {
                /* might overflow.. */
                unsigned int s;
-               s = tempo % ppq;
-               s = (s * 1000) / ppq;
-               tick->resolution = (tempo / ppq) * 1000;
-               tick->resolution += s;
+               s = tmr->tempo % tmr->ppq;
+               s = (s * 1000) / tmr->ppq;
+               tmr->tick.resolution = (tmr->tempo / tmr->ppq) * 1000;
+               tmr->tick.resolution += s;
        }
-       if (tick->resolution <= 0)
-               tick->resolution = 1;
-       snd_seq_timer_update_tick(tick, 0);
+       if (tmr->tick.resolution <= 0)
+               tmr->tick.resolution = 1;
+       snd_seq_timer_update_tick(&tmr->tick, 0);
 }
 
 /* create new timer (constructor) */
@@ -96,7 +95,7 @@ void snd_seq_timer_defaults(struct snd_seq_timer * tmr)
        /* setup defaults */
        tmr->ppq = 96;          /* 96 PPQ */
        tmr->tempo = 500000;    /* 120 BPM */
-       snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq);
+       snd_seq_timer_set_tick_resolution(tmr);
        tmr->running = 0;
 
        tmr->type = SNDRV_SEQ_TIMER_ALSA;
@@ -180,7 +179,7 @@ int snd_seq_timer_set_tempo(struct snd_seq_timer * tmr, int tempo)
        spin_lock_irqsave(&tmr->lock, flags);
        if ((unsigned int)tempo != tmr->tempo) {
                tmr->tempo = tempo;
-               snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq);
+               snd_seq_timer_set_tick_resolution(tmr);
        }
        spin_unlock_irqrestore(&tmr->lock, flags);
        return 0;
@@ -205,7 +204,7 @@ int snd_seq_timer_set_ppq(struct snd_seq_timer * tmr, int ppq)
        }
 
        tmr->ppq = ppq;
-       snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq);
+       snd_seq_timer_set_tick_resolution(tmr);
        spin_unlock_irqrestore(&tmr->lock, flags);
        return 0;
 }
index 252e04ce602f6adf6bf434f0b02edc24c4c8bb76..7f41990ed68b74f557caa6b180cd1b11db3ad2ef 100644 (file)
@@ -45,109 +45,23 @@ MODULE_SUPPORTED_DEVICE("{{ALSA,Dummy soundcard}}");
 #define MAX_PCM_SUBSTREAMS     128
 #define MAX_MIDI_DEVICES       2
 
-#if 0 /* emu10k1 emulation */
-#define MAX_BUFFER_SIZE                (128 * 1024)
-static int emu10k1_playback_constraints(struct snd_pcm_runtime *runtime)
-{
-       int err;
-       err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
-       if (err < 0)
-               return err;
-       err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX);
-       if (err < 0)
-               return err;
-       return 0;
-}
-#define add_playback_constraints emu10k1_playback_constraints
-#endif
-
-#if 0 /* RME9652 emulation */
-#define MAX_BUFFER_SIZE                (26 * 64 * 1024)
-#define USE_FORMATS            SNDRV_PCM_FMTBIT_S32_LE
-#define USE_CHANNELS_MIN       26
-#define USE_CHANNELS_MAX       26
-#define USE_PERIODS_MIN                2
-#define USE_PERIODS_MAX                2
-#endif
-
-#if 0 /* ICE1712 emulation */
-#define MAX_BUFFER_SIZE                (256 * 1024)
-#define USE_FORMATS            SNDRV_PCM_FMTBIT_S32_LE
-#define USE_CHANNELS_MIN       10
-#define USE_CHANNELS_MAX       10
-#define USE_PERIODS_MIN                1
-#define USE_PERIODS_MAX                1024
-#endif
-
-#if 0 /* UDA1341 emulation */
-#define MAX_BUFFER_SIZE                (16380)
-#define USE_FORMATS            SNDRV_PCM_FMTBIT_S16_LE
-#define USE_CHANNELS_MIN       2
-#define USE_CHANNELS_MAX       2
-#define USE_PERIODS_MIN                2
-#define USE_PERIODS_MAX                255
-#endif
-
-#if 0 /* simple AC97 bridge (intel8x0) with 48kHz AC97 only codec */
-#define USE_FORMATS            SNDRV_PCM_FMTBIT_S16_LE
-#define USE_CHANNELS_MIN       2
-#define USE_CHANNELS_MAX       2
-#define USE_RATE               SNDRV_PCM_RATE_48000
-#define USE_RATE_MIN           48000
-#define USE_RATE_MAX           48000
-#endif
-
-#if 0 /* CA0106 */
-#define USE_FORMATS            SNDRV_PCM_FMTBIT_S16_LE
-#define USE_CHANNELS_MIN       2
-#define USE_CHANNELS_MAX       2
-#define USE_RATE               (SNDRV_PCM_RATE_48000|SNDRV_PCM_RATE_96000|SNDRV_PCM_RATE_192000) 
-#define USE_RATE_MIN           48000 
-#define USE_RATE_MAX           192000
-#define MAX_BUFFER_SIZE                ((65536-64)*8)
-#define MAX_PERIOD_SIZE                (65536-64)
-#define USE_PERIODS_MIN                2
-#define USE_PERIODS_MAX                8
-#endif
-
-
 /* defaults */
-#ifndef MAX_BUFFER_SIZE
 #define MAX_BUFFER_SIZE                (64*1024)
-#endif
-#ifndef MAX_PERIOD_SIZE
+#define MIN_PERIOD_SIZE                64
 #define MAX_PERIOD_SIZE                MAX_BUFFER_SIZE
-#endif
-#ifndef USE_FORMATS
 #define USE_FORMATS            (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE)
-#endif
-#ifndef USE_RATE
 #define USE_RATE               SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000
 #define USE_RATE_MIN           5500
 #define USE_RATE_MAX           48000
-#endif
-#ifndef USE_CHANNELS_MIN
 #define USE_CHANNELS_MIN       1
-#endif
-#ifndef USE_CHANNELS_MAX
 #define USE_CHANNELS_MAX       2
-#endif
-#ifndef USE_PERIODS_MIN
 #define USE_PERIODS_MIN        1
-#endif
-#ifndef USE_PERIODS_MAX
 #define USE_PERIODS_MAX        1024
-#endif
-#ifndef add_playback_constraints
-#define add_playback_constraints(x) 0
-#endif
-#ifndef add_capture_constraints
-#define add_capture_constraints(x) 0
-#endif
 
 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 char *model[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = NULL};
 static int pcm_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
 static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8};
 //static int midi_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
@@ -162,6 +76,8 @@ module_param_array(id, charp, NULL, 0444);
 MODULE_PARM_DESC(id, "ID string for dummy soundcard.");
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable this dummy soundcard.");
+module_param_array(model, charp, NULL, 0444);
+MODULE_PARM_DESC(model, "Soundcard model.");
 module_param_array(pcm_devs, int, NULL, 0444);
 MODULE_PARM_DESC(pcm_devs, "PCM devices # (0-4) for dummy driver.");
 module_param_array(pcm_substreams, int, NULL, 0444);
@@ -193,15 +109,120 @@ struct dummy_timer_ops {
        snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *);
 };
 
+struct dummy_model {
+       const char *name;
+       int (*playback_constraints)(struct snd_pcm_runtime *runtime);
+       int (*capture_constraints)(struct snd_pcm_runtime *runtime);
+       u64 formats;
+       size_t buffer_bytes_max;
+       size_t period_bytes_min;
+       size_t period_bytes_max;
+       unsigned int periods_min;
+       unsigned int periods_max;
+       unsigned int rates;
+       unsigned int rate_min;
+       unsigned int rate_max;
+       unsigned int channels_min;
+       unsigned int channels_max;
+};
+
 struct snd_dummy {
        struct snd_card *card;
+       struct dummy_model *model;
        struct snd_pcm *pcm;
+       struct snd_pcm_hardware pcm_hw;
        spinlock_t mixer_lock;
        int mixer_volume[MIXER_ADDR_LAST+1][2];
        int capture_source[MIXER_ADDR_LAST+1][2];
        const struct dummy_timer_ops *timer_ops;
 };
 
+/*
+ * card models
+ */
+
+static int emu10k1_playback_constraints(struct snd_pcm_runtime *runtime)
+{
+       int err;
+       err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+       if (err < 0)
+               return err;
+       err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX);
+       if (err < 0)
+               return err;
+       return 0;
+}
+
+struct dummy_model model_emu10k1 = {
+       .name = "emu10k1",
+       .playback_constraints = emu10k1_playback_constraints,
+       .buffer_bytes_max = 128 * 1024,
+};
+
+struct dummy_model model_rme9652 = {
+       .name = "rme9652",
+       .buffer_bytes_max = 26 * 64 * 1024,
+       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+       .channels_min = 26,
+       .channels_max = 26,
+       .periods_min = 2,
+       .periods_max = 2,
+};
+
+struct dummy_model model_ice1712 = {
+       .name = "ice1712",
+       .buffer_bytes_max = 256 * 1024,
+       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+       .channels_min = 10,
+       .channels_max = 10,
+       .periods_min = 1,
+       .periods_max = 1024,
+};
+
+struct dummy_model model_uda1341 = {
+       .name = "uda1341",
+       .buffer_bytes_max = 16380,
+       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       .channels_min = 2,
+       .channels_max = 2,
+       .periods_min = 2,
+       .periods_max = 255,
+};
+
+struct dummy_model model_ac97 = {
+       .name = "ac97",
+       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       .channels_min = 2,
+       .channels_max = 2,
+       .rates = SNDRV_PCM_RATE_48000,
+       .rate_min = 48000,
+       .rate_max = 48000,
+};
+
+struct dummy_model model_ca0106 = {
+       .name = "ca0106",
+       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       .buffer_bytes_max = ((65536-64)*8),
+       .period_bytes_max = (65536-64),
+       .periods_min = 2,
+       .periods_max = 8,
+       .channels_min = 2,
+       .channels_max = 2,
+       .rates = SNDRV_PCM_RATE_48000|SNDRV_PCM_RATE_96000|SNDRV_PCM_RATE_192000,
+       .rate_min = 48000,
+       .rate_max = 192000,
+};
+
+struct dummy_model *dummy_models[] = {
+       &model_emu10k1,
+       &model_rme9652,
+       &model_ice1712,
+       &model_uda1341,
+       &model_ac97,
+       &model_ca0106,
+       NULL
+};
+
 /*
  * system timer interface
  */
@@ -509,7 +530,7 @@ static struct snd_pcm_hardware dummy_pcm_hardware = {
        .channels_min =         USE_CHANNELS_MIN,
        .channels_max =         USE_CHANNELS_MAX,
        .buffer_bytes_max =     MAX_BUFFER_SIZE,
-       .period_bytes_min =     64,
+       .period_bytes_min =     MIN_PERIOD_SIZE,
        .period_bytes_max =     MAX_PERIOD_SIZE,
        .periods_min =          USE_PERIODS_MIN,
        .periods_max =          USE_PERIODS_MAX,
@@ -538,6 +559,7 @@ static int dummy_pcm_hw_free(struct snd_pcm_substream *substream)
 static int dummy_pcm_open(struct snd_pcm_substream *substream)
 {
        struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
+       struct dummy_model *model = dummy->model;
        struct snd_pcm_runtime *runtime = substream->runtime;
        int err;
 
@@ -551,7 +573,7 @@ static int dummy_pcm_open(struct snd_pcm_substream *substream)
        if (err < 0)
                return err;
 
-       runtime->hw = dummy_pcm_hardware;
+       runtime->hw = dummy->pcm_hw;
        if (substream->pcm->device & 1) {
                runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;
                runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
@@ -560,10 +582,16 @@ static int dummy_pcm_open(struct snd_pcm_substream *substream)
                runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP |
                                      SNDRV_PCM_INFO_MMAP_VALID);
 
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               err = add_playback_constraints(substream->runtime);
-       else
-               err = add_capture_constraints(substream->runtime);
+       if (model == NULL)
+               return 0;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               if (model->playback_constraints)
+                       err = model->playback_constraints(substream->runtime);
+       } else {
+               if (model->capture_constraints)
+                       err = model->capture_constraints(substream->runtime);
+       }
        if (err < 0) {
                dummy->timer_ops->free(substream);
                return err;
@@ -823,17 +851,19 @@ static int __devinit snd_card_dummy_new_mixer(struct snd_dummy *dummy)
 /*
  * proc interface
  */
-static void print_formats(struct snd_info_buffer *buffer)
+static void print_formats(struct snd_dummy *dummy,
+                         struct snd_info_buffer *buffer)
 {
        int i;
 
        for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) {
-               if (dummy_pcm_hardware.formats & (1ULL << i))
+               if (dummy->pcm_hw.formats & (1ULL << i))
                        snd_iprintf(buffer, " %s", snd_pcm_format_name(i));
        }
 }
 
-static void print_rates(struct snd_info_buffer *buffer)
+static void print_rates(struct snd_dummy *dummy,
+                       struct snd_info_buffer *buffer)
 {
        static int rates[] = {
                5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000,
@@ -841,19 +871,19 @@ static void print_rates(struct snd_info_buffer *buffer)
        };
        int i;
 
-       if (dummy_pcm_hardware.rates & SNDRV_PCM_RATE_CONTINUOUS)
+       if (dummy->pcm_hw.rates & SNDRV_PCM_RATE_CONTINUOUS)
                snd_iprintf(buffer, " continuous");
-       if (dummy_pcm_hardware.rates & SNDRV_PCM_RATE_KNOT)
+       if (dummy->pcm_hw.rates & SNDRV_PCM_RATE_KNOT)
                snd_iprintf(buffer, " knot");
        for (i = 0; i < ARRAY_SIZE(rates); i++)
-               if (dummy_pcm_hardware.rates & (1 << i))
+               if (dummy->pcm_hw.rates & (1 << i))
                        snd_iprintf(buffer, " %d", rates[i]);
 }
 
-#define get_dummy_int_ptr(ofs) \
-       (unsigned int *)((char *)&dummy_pcm_hardware + (ofs))
-#define get_dummy_ll_ptr(ofs) \
-       (unsigned long long *)((char *)&dummy_pcm_hardware + (ofs))
+#define get_dummy_int_ptr(dummy, ofs) \
+       (unsigned int *)((char *)&((dummy)->pcm_hw) + (ofs))
+#define get_dummy_ll_ptr(dummy, ofs) \
+       (unsigned long long *)((char *)&((dummy)->pcm_hw) + (ofs))
 
 struct dummy_hw_field {
        const char *name;
@@ -884,20 +914,21 @@ static struct dummy_hw_field fields[] = {
 static void dummy_proc_read(struct snd_info_entry *entry,
                            struct snd_info_buffer *buffer)
 {
+       struct snd_dummy *dummy = entry->private_data;
        int i;
 
        for (i = 0; i < ARRAY_SIZE(fields); i++) {
                snd_iprintf(buffer, "%s ", fields[i].name);
                if (fields[i].size == sizeof(int))
                        snd_iprintf(buffer, fields[i].format,
-                                   *get_dummy_int_ptr(fields[i].offset));
+                               *get_dummy_int_ptr(dummy, fields[i].offset));
                else
                        snd_iprintf(buffer, fields[i].format,
-                                   *get_dummy_ll_ptr(fields[i].offset));
+                               *get_dummy_ll_ptr(dummy, fields[i].offset));
                if (!strcmp(fields[i].name, "formats"))
-                       print_formats(buffer);
+                       print_formats(dummy, buffer);
                else if (!strcmp(fields[i].name, "rates"))
-                       print_rates(buffer);
+                       print_rates(dummy, buffer);
                snd_iprintf(buffer, "\n");
        }
 }
@@ -905,6 +936,7 @@ static void dummy_proc_read(struct snd_info_entry *entry,
 static void dummy_proc_write(struct snd_info_entry *entry,
                             struct snd_info_buffer *buffer)
 {
+       struct snd_dummy *dummy = entry->private_data;
        char line[64];
 
        while (!snd_info_get_line(buffer, line, sizeof(line))) {
@@ -924,9 +956,9 @@ static void dummy_proc_write(struct snd_info_entry *entry,
                if (strict_strtoull(item, 0, &val))
                        continue;
                if (fields[i].size == sizeof(int))
-                       *get_dummy_int_ptr(fields[i].offset) = val;
+                       *get_dummy_int_ptr(dummy, fields[i].offset) = val;
                else
-                       *get_dummy_ll_ptr(fields[i].offset) = val;
+                       *get_dummy_ll_ptr(dummy, fields[i].offset) = val;
        }
 }
 
@@ -938,6 +970,7 @@ static void __devinit dummy_proc_init(struct snd_dummy *chip)
                snd_info_set_text_ops(entry, chip, dummy_proc_read);
                entry->c.text.write = dummy_proc_write;
                entry->mode |= S_IWUSR;
+               entry->private_data = chip;
        }
 }
 #else
@@ -948,6 +981,7 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr)
 {
        struct snd_card *card;
        struct snd_dummy *dummy;
+       struct dummy_model *m = NULL, **mdl;
        int idx, err;
        int dev = devptr->id;
 
@@ -957,6 +991,15 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr)
                return err;
        dummy = card->private_data;
        dummy->card = card;
+       for (mdl = dummy_models; *mdl && model[dev]; mdl++) {
+               if (strcmp(model[dev], (*mdl)->name) == 0) {
+                       printk(KERN_INFO
+                               "snd-dummy: Using model '%s' for card %i\n",
+                               (*mdl)->name, card->number);
+                       m = dummy->model = *mdl;
+                       break;
+               }
+       }
        for (idx = 0; idx < MAX_PCM_DEVICES && idx < pcm_devs[dev]; idx++) {
                if (pcm_substreams[dev] < 1)
                        pcm_substreams[dev] = 1;
@@ -966,6 +1009,33 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr)
                if (err < 0)
                        goto __nodev;
        }
+
+       dummy->pcm_hw = dummy_pcm_hardware;
+       if (m) {
+               if (m->formats)
+                       dummy->pcm_hw.formats = m->formats;
+               if (m->buffer_bytes_max)
+                       dummy->pcm_hw.buffer_bytes_max = m->buffer_bytes_max;
+               if (m->period_bytes_min)
+                       dummy->pcm_hw.period_bytes_min = m->period_bytes_min;
+               if (m->period_bytes_max)
+                       dummy->pcm_hw.period_bytes_max = m->period_bytes_max;
+               if (m->periods_min)
+                       dummy->pcm_hw.periods_min = m->periods_min;
+               if (m->periods_max)
+                       dummy->pcm_hw.periods_max = m->periods_max;
+               if (m->rates)
+                       dummy->pcm_hw.rates = m->rates;
+               if (m->rate_min)
+                       dummy->pcm_hw.rate_min = m->rate_min;
+               if (m->rate_max)
+                       dummy->pcm_hw.rate_max = m->rate_max;
+               if (m->channels_min)
+                       dummy->pcm_hw.channels_min = m->channels_min;
+               if (m->channels_max)
+                       dummy->pcm_hw.channels_max = m->channels_max;
+       }
+
        err = snd_card_dummy_new_mixer(dummy);
        if (err < 0)
                goto __nodev;
index 6644d0034fbaa357b88f7207b676343881ff4207..35a2f71a6af5202f49b2e3339c68ebb2575abe7e 100644 (file)
@@ -46,7 +46,6 @@
  */
 
 #include <linux/slab.h>
-#include <linux/vmalloc.h>
 #include <linux/delay.h>
 #include <sound/core.h>
 #include <sound/asoundef.h>
 #include "vx_cmd.h"
 
 
-/*
- * we use a vmalloc'ed (sg-)buffer
- */
-
-/* get the physical page pointer on the given offset */
-static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
-                                            unsigned long offset)
-{
-       void *pageptr = subs->runtime->dma_area + offset;
-       return vmalloc_to_page(pageptr);
-}
-
-/*
- * allocate a buffer via vmalloc_32().
- * called from hw_params
- * NOTE: this may be called not only once per pcm open!
- */
-static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t size)
-{
-       struct snd_pcm_runtime *runtime = subs->runtime;
-       if (runtime->dma_area) {
-               /* already allocated */
-               if (runtime->dma_bytes >= size)
-                       return 0; /* already enough large */
-               vfree(runtime->dma_area);
-       }
-       runtime->dma_area = vmalloc_32(size);
-       if (! runtime->dma_area)
-               return -ENOMEM;
-       memset(runtime->dma_area, 0, size);
-       runtime->dma_bytes = size;
-       return 1; /* changed */
-}
-
-/*
- * free the buffer.
- * called from hw_free callback
- * NOTE: this may be called not only once per pcm open!
- */
-static int snd_pcm_free_vmalloc_buffer(struct snd_pcm_substream *subs)
-{
-       struct snd_pcm_runtime *runtime = subs->runtime;
-
-       vfree(runtime->dma_area);
-       runtime->dma_area = NULL;
-       return 0;
-}
-
-
 /*
  * read three pending pcm bytes via inb()
  */
@@ -865,7 +815,8 @@ static snd_pcm_uframes_t vx_pcm_playback_pointer(struct snd_pcm_substream *subs)
 static int vx_pcm_hw_params(struct snd_pcm_substream *subs,
                                     struct snd_pcm_hw_params *hw_params)
 {
-       return snd_pcm_alloc_vmalloc_buffer(subs, params_buffer_bytes(hw_params));
+       return snd_pcm_lib_alloc_vmalloc_32_buffer
+                                       (subs, params_buffer_bytes(hw_params));
 }
 
 /*
@@ -873,7 +824,7 @@ static int vx_pcm_hw_params(struct snd_pcm_substream *subs,
  */
 static int vx_pcm_hw_free(struct snd_pcm_substream *subs)
 {
-       return snd_pcm_free_vmalloc_buffer(subs);
+       return snd_pcm_lib_free_vmalloc_buffer(subs);
 }
 
 /*
@@ -953,7 +904,8 @@ static struct snd_pcm_ops vx_pcm_playback_ops = {
        .prepare =      vx_pcm_prepare,
        .trigger =      vx_pcm_trigger,
        .pointer =      vx_pcm_playback_pointer,
-       .page =         snd_pcm_get_vmalloc_page,
+       .page =         snd_pcm_lib_get_vmalloc_page,
+       .mmap =         snd_pcm_lib_mmap_vmalloc,
 };
 
 
@@ -1173,7 +1125,8 @@ static struct snd_pcm_ops vx_pcm_capture_ops = {
        .prepare =      vx_pcm_prepare,
        .trigger =      vx_pcm_trigger,
        .pointer =      vx_pcm_capture_pointer,
-       .page =         snd_pcm_get_vmalloc_page,
+       .page =         snd_pcm_lib_get_vmalloc_page,
+       .mmap =         snd_pcm_lib_mmap_vmalloc,
 };
 
 
index 02fe81ca88fde87c29487c8cc09afcdda9a0810c..755a0a5f0e3fbaed9aa1a68a83cc04cf1a24be91 100644 (file)
@@ -63,15 +63,16 @@ config SND_AD1848
          will be called snd-ad1848.
 
 config SND_ALS100
-       tristate "Avance Logic ALS100/ALS120"
+       tristate "Diamond Tech. DT-019x and Avance Logic ALSxxx"
        depends on PNP
        select ISAPNP
        select SND_OPL3_LIB
        select SND_MPU401_UART
        select SND_SB16_DSP
        help
-         Say Y here to include support for soundcards based on Avance
-         Logic ALS100, ALS110, ALS120 and ALS200 chips.
+         Say Y here to include support for soundcards based on the
+         Diamond Technologies DT-019X or Avance Logic chips: ALS007,
+         ALS100, ALS110, ALS120 and ALS200 chips.
 
          To compile this driver as a module, choose M here: the module
          will be called snd-als100.
@@ -127,20 +128,6 @@ config SND_CS4236
          To compile this driver as a module, choose M here: the module
          will be called snd-cs4236.
 
-config SND_DT019X
-       tristate "Diamond Technologies DT-019X, Avance Logic ALS-007"
-       depends on PNP
-       select ISAPNP
-       select SND_OPL3_LIB
-       select SND_MPU401_UART
-       select SND_SB16_DSP
-       help
-         Say Y here to include support for soundcards based on the
-         Diamond Technologies DT-019X or Avance Logic ALS-007 chips.
-
-         To compile this driver as a module, choose M here: the module
-         will be called snd-dt019x.
-
 config SND_ES968
        tristate "Generic ESS ES968 driver"
        depends on PNP
@@ -252,6 +239,22 @@ config SND_INTERWAVE_STB
          To compile this driver as a module, choose M here: the module
          will be called snd-interwave-stb.
 
+config SND_JAZZ16
+       tristate "Media Vision Jazz16 card and compatibles"
+       select SND_OPL3_LIB
+       select SND_MPU401_UART
+       select SND_SB8_DSP
+       help
+         Say Y here to include support for soundcards based on the
+         Media Vision Jazz16 chipset: digital chip MVD1216 (Jazz16),
+         codec MVA416 (CS4216) and mixer MVA514 (ICS2514).
+         Media Vision's Jazz16 cards were sold under names Pro Sonic 16,
+         Premium 3-D and Pro 3-D. There were also OEMs cards with the
+         Jazz16 chipset.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-jazz16.
+
 config SND_OPL3SA2
        tristate "Yamaha OPL3-SA2/SA3"
        select SND_OPL3_LIB
index b906b9a1a81e622654fa8628f62b9547679afe77..c73d30c4f46289c982ff793f42f6b3a6828052b8 100644 (file)
@@ -7,7 +7,6 @@ snd-adlib-objs := adlib.o
 snd-als100-objs := als100.o
 snd-azt2320-objs := azt2320.o
 snd-cmi8330-objs := cmi8330.o
-snd-dt019x-objs := dt019x.o
 snd-es18xx-objs := es18xx.o
 snd-opl3sa2-objs := opl3sa2.o
 snd-sc6000-objs := sc6000.o
@@ -19,7 +18,6 @@ obj-$(CONFIG_SND_ADLIB) += snd-adlib.o
 obj-$(CONFIG_SND_ALS100) += snd-als100.o
 obj-$(CONFIG_SND_AZT2320) += snd-azt2320.o
 obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o
-obj-$(CONFIG_SND_DT019X) += snd-dt019x.o
 obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o
 obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o
 obj-$(CONFIG_SND_SC6000) += snd-sc6000.o
index 5fd52e4d707998769f317b8dbbaf3d7e0839f9f4..20becc89f6f6f45ab35a456591add0b93f89f038 100644 (file)
@@ -2,9 +2,13 @@
 /*
     card-als100.c - driver for Avance Logic ALS100 based soundcards.
     Copyright (C) 1999-2000 by Massimo Piccioni <dafastidio@libero.it>
+    Copyright (C) 1999-2002 by Massimo Piccioni <dafastidio@libero.it>
 
     Thanks to Pierfrancesco 'qM2' Passerini.
 
+    Generalised for soundcards based on DT-0196 and ALS-007 chips
+    by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>: June 2002.
+
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; either version 2 of the License, or
 
 #define PFX "als100: "
 
-MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
-MODULE_DESCRIPTION("Avance Logic ALS1X0");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS100 - PRO16PNP},"
+MODULE_DESCRIPTION("Avance Logic ALS007/ALS1X0");
+MODULE_SUPPORTED_DEVICE("{{Diamond Technologies DT-019X},"
+               "{Avance Logic ALS-007}}"
+               "{{Avance Logic,ALS100 - PRO16PNP},"
                "{Avance Logic,ALS110},"
                "{Avance Logic,ALS120},"
                "{Avance Logic,ALS200},"
@@ -45,9 +49,12 @@ MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS100 - PRO16PNP},"
                "{Avance Logic,ALS120},"
                "{RTL,RTL3000}}");
 
+MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
+MODULE_LICENSE("GPL");
+
 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_ISAPNP; /* Enable this card */
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;    /* PnP setup */
 static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;        /* PnP setup */
 static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
@@ -57,14 +64,15 @@ static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;   /* PnP setup */
 static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;     /* PnP setup */
 
 module_param_array(index, int, NULL, 0444);
-MODULE_PARM_DESC(index, "Index value for als100 based soundcard.");
+MODULE_PARM_DESC(index, "Index value for Avance Logic based soundcard.");
 module_param_array(id, charp, NULL, 0444);
-MODULE_PARM_DESC(id, "ID string for als100 based soundcard.");
+MODULE_PARM_DESC(id, "ID string for Avance Logic based soundcard.");
 module_param_array(enable, bool, NULL, 0444);
-MODULE_PARM_DESC(enable, "Enable als100 based soundcard.");
+MODULE_PARM_DESC(enable, "Enable Avance Logic based soundcard.");
+
+MODULE_ALIAS("snd-dt019x");
 
 struct snd_card_als100 {
-       int dev_no;
        struct pnp_dev *dev;
        struct pnp_dev *devmpu;
        struct pnp_dev *devopl;
@@ -72,25 +80,43 @@ struct snd_card_als100 {
 };
 
 static struct pnp_card_device_id snd_als100_pnpids[] = {
+       /* DT197A30 */
+       { .id = "RWB1688",
+         .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } },
+         .driver_data = SB_HW_DT019X },
+       /* DT0196 / ALS-007 */
+       { .id = "ALS0007",
+         .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } },
+         .driver_data = SB_HW_DT019X },
        /* ALS100 - PRO16PNP */
-       { .id = "ALS0001", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } } },
+       { .id = "ALS0001",
+         .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } },
+         .driver_data = SB_HW_ALS100 },
        /* ALS110 - MF1000 - Digimate 3D Sound */
-       { .id = "ALS0110", .devs = { { "@@@1001" }, { "@X@1001" }, { "@H@1001" } } },
+       { .id = "ALS0110",
+         .devs = { { "@@@1001" }, { "@X@1001" }, { "@H@1001" } },
+         .driver_data = SB_HW_ALS100 },
        /* ALS120 */
-       { .id = "ALS0120", .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } } },
+       { .id = "ALS0120",
+         .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } },
+         .driver_data = SB_HW_ALS100 },
        /* ALS200 */
-       { .id = "ALS0200", .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0001" } } },
+       { .id = "ALS0200",
+         .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0001" } },
+         .driver_data = SB_HW_ALS100 },
        /* ALS200 OEM */
-       { .id = "ALS0200", .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0020" } } },
+       { .id = "ALS0200",
+         .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0020" } },
+         .driver_data = SB_HW_ALS100 },
        /* RTL3000 */
-       { .id = "RTL3000", .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } } },
-       { .id = "", } /* end */
+       { .id = "RTL3000",
+         .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } },
+         .driver_data = SB_HW_ALS100 },
+       { .id = "" } /* end */
 };
 
 MODULE_DEVICE_TABLE(pnp_card, snd_als100_pnpids);
 
-#define DRIVER_NAME    "snd-card-als100"
-
 static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard,
                                         struct pnp_card_link *card,
                                         const struct pnp_card_device_id *id)
@@ -113,8 +139,12 @@ static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard,
                return err;
        }
        port[dev] = pnp_port_start(pdev, 0);
-       dma8[dev] = pnp_dma(pdev, 1);
-       dma16[dev] = pnp_dma(pdev, 0);
+       if (id->driver_data == SB_HW_DT019X)
+               dma8[dev] = pnp_dma(pdev, 0);
+       else {
+               dma8[dev] = pnp_dma(pdev, 1);
+               dma16[dev] = pnp_dma(pdev, 0);
+       }
        irq[dev] = pnp_irq(pdev, 0);
 
        pdev = acard->devmpu;
@@ -175,22 +205,33 @@ static int __devinit snd_card_als100_probe(int dev,
        }
        snd_card_set_dev(card, &pcard->card->dev);
 
-       if ((error = snd_sbdsp_create(card, port[dev],
-                                     irq[dev],
-                                     snd_sb16dsp_interrupt,
-                                     dma8[dev],
-                                     dma16[dev],
-                                     SB_HW_ALS100, &chip)) < 0) {
+       if (pid->driver_data == SB_HW_DT019X)
+               dma16[dev] = -1;
+
+       error = snd_sbdsp_create(card, port[dev], irq[dev],
+                                 snd_sb16dsp_interrupt,
+                                 dma8[dev], dma16[dev],
+                                 pid->driver_data,
+                                 &chip);
+       if (error < 0) {
                snd_card_free(card);
                return error;
        }
        acard->chip = chip;
 
-       strcpy(card->driver, "ALS100");
-       strcpy(card->shortname, "Avance Logic ALS100");
-       sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d",
-               card->shortname, chip->name, chip->port,
-               irq[dev], dma8[dev], dma16[dev]);
+       if (pid->driver_data == SB_HW_DT019X) {
+               strcpy(card->driver, "DT-019X");
+               strcpy(card->shortname, "Diamond Tech. DT-019X");
+               sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d",
+                       card->shortname, chip->name, chip->port,
+                       irq[dev], dma8[dev]);
+       } else {
+               strcpy(card->driver, "ALS100");
+               strcpy(card->shortname, "Avance Logic ALS100");
+               sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d",
+                       card->shortname, chip->name, chip->port,
+                       irq[dev], dma8[dev], dma16[dev]);
+       }
 
        if ((error = snd_sb16dsp_pcm(chip, 0, NULL)) < 0) {
                snd_card_free(card);
@@ -203,9 +244,19 @@ static int __devinit snd_card_als100_probe(int dev,
        }
 
        if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
-               if (snd_mpu401_uart_new(card, 0, MPU401_HW_ALS100,
+               int mpu_type = MPU401_HW_ALS100;
+
+               if (mpu_irq[dev] == SNDRV_AUTO_IRQ)
+                       mpu_irq[dev] = -1;
+
+               if (pid->driver_data == SB_HW_DT019X)
+                       mpu_type = MPU401_HW_MPU401;
+
+               if (snd_mpu401_uart_new(card, 0,
+                                       mpu_type,
                                        mpu_port[dev], 0, 
-                                       mpu_irq[dev], IRQF_DISABLED,
+                                       mpu_irq[dev],
+                                       mpu_irq[dev] >= 0 ? IRQF_DISABLED : 0,
                                        NULL) < 0)
                        snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]);
        }
@@ -291,7 +342,7 @@ static int snd_als100_pnp_resume(struct pnp_card_link *pcard)
 
 static struct pnp_card_driver als100_pnpc_driver = {
        .flags          = PNP_DRIVER_RES_DISABLE,
-        .name           = "als100",
+       .name           = "als100",
         .id_table       = snd_als100_pnpids,
         .probe          = snd_als100_pnp_detect,
         .remove         = __devexit_p(snd_als100_pnp_remove),
@@ -312,7 +363,7 @@ static int __init alsa_card_als100_init(void)
        if (!als100_devices) {
                pnp_unregister_card_driver(&als100_pnpc_driver);
 #ifdef MODULE
-               snd_printk(KERN_ERR "no ALS100 based soundcards found\n");
+               snd_printk(KERN_ERR "no Avance Logic based soundcards found\n");
 #endif
                return -ENODEV;
        }
diff --git a/sound/isa/dt019x.c b/sound/isa/dt019x.c
deleted file mode 100644 (file)
index 80f5b1a..0000000
+++ /dev/null
@@ -1,321 +0,0 @@
-
-/*
-    dt019x.c - driver for Diamond Technologies DT-0197H based soundcards.
-    Copyright (C) 1999, 2002 by Massimo Piccioni <dafastidio@libero.it>
-
-    Generalised for soundcards based on DT-0196 and ALS-007 chips 
-    by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>: June 2002.
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the 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/wait.h>
-#include <linux/pnp.h>
-#include <linux/moduleparam.h>
-#include <sound/core.h>
-#include <sound/initval.h>
-#include <sound/mpu401.h>
-#include <sound/opl3.h>
-#include <sound/sb.h>
-
-#define PFX "dt019x: "
-
-MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
-MODULE_DESCRIPTION("Diamond Technologies DT-019X / Avance Logic ALS-007");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Diamond Technologies DT-019X},"
-              "{Avance Logic ALS-007}}");
-
-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 port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;    /* PnP setup */
-static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;        /* PnP setup */
-static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
-static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;       /* PnP setup */
-static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;   /* PnP setup */
-static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;      /* PnP setup */
-
-module_param_array(index, int, NULL, 0444);
-MODULE_PARM_DESC(index, "Index value for DT-019X based soundcard.");
-module_param_array(id, charp, NULL, 0444);
-MODULE_PARM_DESC(id, "ID string for DT-019X based soundcard.");
-module_param_array(enable, bool, NULL, 0444);
-MODULE_PARM_DESC(enable, "Enable DT-019X based soundcard.");
-
-struct snd_card_dt019x {
-       struct pnp_dev *dev;
-       struct pnp_dev *devmpu;
-       struct pnp_dev *devopl;
-       struct snd_sb *chip;
-};
-
-static struct pnp_card_device_id snd_dt019x_pnpids[] = {
-       /* DT197A30 */
-       { .id = "RWB1688", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" }, } },
-       /* DT0196 / ALS-007 */
-       { .id = "ALS0007", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" }, } },
-       { .id = "",  }
-};
-
-MODULE_DEVICE_TABLE(pnp_card, snd_dt019x_pnpids);
-
-
-#define DRIVER_NAME    "snd-card-dt019x"
-
-
-static int __devinit snd_card_dt019x_pnp(int dev, struct snd_card_dt019x *acard,
-                                        struct pnp_card_link *card,
-                                        const struct pnp_card_device_id *pid)
-{
-       struct pnp_dev *pdev;
-       int err;
-
-       acard->dev = pnp_request_card_device(card, pid->devs[0].id, NULL);
-       if (acard->dev == NULL)
-               return -ENODEV;
-
-       acard->devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL);
-       acard->devopl = pnp_request_card_device(card, pid->devs[2].id, NULL);
-
-       pdev = acard->dev;
-
-       err = pnp_activate_dev(pdev);
-       if (err < 0) {
-               snd_printk(KERN_ERR PFX "DT-019X AUDIO pnp configure failure\n");
-               return err;
-       }
-
-       port[dev] = pnp_port_start(pdev, 0);
-       dma8[dev] = pnp_dma(pdev, 0);
-       irq[dev] = pnp_irq(pdev, 0);
-       snd_printdd("dt019x: found audio interface: port=0x%lx, irq=0x%x, dma=0x%x\n",
-                       port[dev],irq[dev],dma8[dev]);
-
-       pdev = acard->devmpu;
-       if (pdev != NULL) {
-               err = pnp_activate_dev(pdev);
-               if (err < 0) {
-                       pnp_release_card_device(pdev);
-                       snd_printk(KERN_ERR PFX "DT-019X MPU401 pnp configure failure, skipping\n");
-                       goto __mpu_error;
-               }
-               mpu_port[dev] = pnp_port_start(pdev, 0);
-               mpu_irq[dev] = pnp_irq(pdev, 0);
-               snd_printdd("dt019x: found MPU-401: port=0x%lx, irq=0x%x\n",
-                               mpu_port[dev],mpu_irq[dev]);
-       } else {
-       __mpu_error:
-               acard->devmpu = NULL;
-               mpu_port[dev] = -1;
-       }
-
-       pdev = acard->devopl;
-       if (pdev != NULL) {
-               err = pnp_activate_dev(pdev);
-               if (err < 0) {
-                       pnp_release_card_device(pdev);
-                       snd_printk(KERN_ERR PFX "DT-019X OPL3 pnp configure failure, skipping\n");
-                       goto __fm_error;
-               }
-               fm_port[dev] = pnp_port_start(pdev, 0);
-               snd_printdd("dt019x: found OPL3 synth: port=0x%lx\n",fm_port[dev]);
-       } else {
-       __fm_error:
-               acard->devopl = NULL;
-               fm_port[dev] = -1;
-       }
-
-       return 0;
-}
-
-static int __devinit snd_card_dt019x_probe(int dev, struct pnp_card_link *pcard, const struct pnp_card_device_id *pid)
-{
-       int error;
-       struct snd_sb *chip;
-       struct snd_card *card;
-       struct snd_card_dt019x *acard;
-       struct snd_opl3 *opl3;
-
-       error = snd_card_create(index[dev], id[dev], THIS_MODULE,
-                               sizeof(struct snd_card_dt019x), &card);
-       if (error < 0)
-               return error;
-       acard = card->private_data;
-
-       snd_card_set_dev(card, &pcard->card->dev);
-       if ((error = snd_card_dt019x_pnp(dev, acard, pcard, pid))) {
-               snd_card_free(card);
-               return error;
-       }
-
-       if ((error = snd_sbdsp_create(card, port[dev],
-                                     irq[dev],
-                                     snd_sb16dsp_interrupt,
-                                     dma8[dev],
-                                     -1,
-                                     SB_HW_DT019X,
-                                     &chip)) < 0) {
-               snd_card_free(card);
-               return error;
-       }
-       acard->chip = chip;
-
-       strcpy(card->driver, "DT-019X");
-       strcpy(card->shortname, "Diamond Tech. DT-019X");
-       sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d",
-               card->shortname, chip->name, chip->port,
-               irq[dev], dma8[dev]);
-
-       if ((error = snd_sb16dsp_pcm(chip, 0, NULL)) < 0) {
-               snd_card_free(card);
-               return error;
-       }
-       if ((error = snd_sbmixer_new(chip)) < 0) {
-               snd_card_free(card);
-               return error;
-       }
-
-       if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
-               if (mpu_irq[dev] == SNDRV_AUTO_IRQ)
-                       mpu_irq[dev] = -1;
-               if (snd_mpu401_uart_new(card, 0,
-/*                                     MPU401_HW_SB,*/
-                                       MPU401_HW_MPU401,
-                                       mpu_port[dev], 0,
-                                       mpu_irq[dev],
-                                       mpu_irq[dev] >= 0 ? IRQF_DISABLED : 0,
-                                       NULL) < 0)
-                       snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx ?\n", mpu_port[dev]);
-       }
-
-       if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
-               if (snd_opl3_create(card,
-                                   fm_port[dev],
-                                   fm_port[dev] + 2,
-                                   OPL3_HW_AUTO, 0, &opl3) < 0) {
-                       snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx ?\n",
-                                  fm_port[dev], fm_port[dev] + 2);
-               } else {
-                       if ((error = snd_opl3_timer_new(opl3, 0, 1)) < 0) {
-                               snd_card_free(card);
-                               return error;
-                       }
-                       if ((error = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
-                               snd_card_free(card);
-                               return error;
-                       }
-               }
-       }
-
-       if ((error = snd_card_register(card)) < 0) {
-               snd_card_free(card);
-               return error;
-       }
-       pnp_set_card_drvdata(pcard, card);
-       return 0;
-}
-
-static unsigned int __devinitdata dt019x_devices;
-
-static int __devinit snd_dt019x_pnp_probe(struct pnp_card_link *card,
-                                         const struct pnp_card_device_id *pid)
-{
-       static int dev;
-       int res;
-
-       for ( ; dev < SNDRV_CARDS; dev++) {
-               if (!enable[dev])
-                       continue;
-               res = snd_card_dt019x_probe(dev, card, pid);
-               if (res < 0)
-                       return res;
-               dev++;
-               dt019x_devices++;
-               return 0;
-       }
-       return -ENODEV;
-}
-
-static void __devexit snd_dt019x_pnp_remove(struct pnp_card_link * pcard)
-{
-       snd_card_free(pnp_get_card_drvdata(pcard));
-       pnp_set_card_drvdata(pcard, NULL);
-}
-
-#ifdef CONFIG_PM
-static int snd_dt019x_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state)
-{
-       struct snd_card *card = pnp_get_card_drvdata(pcard);
-       struct snd_card_dt019x *acard = card->private_data;
-       struct snd_sb *chip = acard->chip;
-
-       snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
-       snd_pcm_suspend_all(chip->pcm);
-       snd_sbmixer_suspend(chip);
-       return 0;
-}
-
-static int snd_dt019x_pnp_resume(struct pnp_card_link *pcard)
-{
-       struct snd_card *card = pnp_get_card_drvdata(pcard);
-       struct snd_card_dt019x *acard = card->private_data;
-       struct snd_sb *chip = acard->chip;
-
-       snd_sbdsp_reset(chip);
-       snd_sbmixer_resume(chip);
-       snd_power_change_state(card, SNDRV_CTL_POWER_D0);
-       return 0;
-}
-#endif
-
-static struct pnp_card_driver dt019x_pnpc_driver = {
-       .flags          = PNP_DRIVER_RES_DISABLE,
-       .name           = "dt019x",
-       .id_table       = snd_dt019x_pnpids,
-       .probe          = snd_dt019x_pnp_probe,
-       .remove         = __devexit_p(snd_dt019x_pnp_remove),
-#ifdef CONFIG_PM
-       .suspend        = snd_dt019x_pnp_suspend,
-       .resume         = snd_dt019x_pnp_resume,
-#endif
-};
-
-static int __init alsa_card_dt019x_init(void)
-{
-       int err;
-
-       err = pnp_register_card_driver(&dt019x_pnpc_driver);
-       if (err)
-               return err;
-
-       if (!dt019x_devices) {
-               pnp_unregister_card_driver(&dt019x_pnpc_driver);
-#ifdef MODULE
-               snd_printk(KERN_ERR "no DT-019X / ALS-007 based soundcards found\n");
-#endif
-               return -ENODEV;
-       }
-       return 0;
-}
-
-static void __exit alsa_card_dt019x_exit(void)
-{
-       pnp_unregister_card_driver(&dt019x_pnpc_driver);
-}
-
-module_init(alsa_card_dt019x_init)
-module_exit(alsa_card_dt019x_exit)
index c8a8da0d403616f48a3c39d0dc50dcffce8f1e91..a4af53b5c1cfefe30eaf0703ef7eea9dacdfb642 100644 (file)
@@ -33,6 +33,7 @@
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <sound/core.h>
+#include <sound/tlv.h>
 #include <sound/wss.h>
 #include <sound/mpu401.h>
 #include <sound/opl3.h>
@@ -546,6 +547,93 @@ __skip_mpu:
 
 #ifdef OPTi93X
 
+static const DECLARE_TLV_DB_SCALE(db_scale_5bit_3db_step, -9300, 300, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_4bit_12db_max, -3300, 300, 0);
+
+static struct snd_kcontrol_new snd_opti93x_controls[] = {
+WSS_DOUBLE("Master Playback Switch", 0,
+               OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1),
+WSS_DOUBLE_TLV("Master Playback Volume", 0,
+               OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1,
+               db_scale_5bit_3db_step),
+WSS_DOUBLE_TLV("PCM Playback Volume", 0,
+               CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 31, 1,
+               db_scale_5bit),
+WSS_DOUBLE_TLV("FM Playback Volume", 0,
+               CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 1, 1, 15, 1,
+               db_scale_4bit_12db_max),
+WSS_DOUBLE("Line Playback Switch", 0,
+               CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
+WSS_DOUBLE_TLV("Line Playback Volume", 0,
+               CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 15, 1,
+               db_scale_4bit_12db_max),
+WSS_DOUBLE("Mic Playback Switch", 0,
+               OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE_TLV("Mic Playback Volume", 0,
+               OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1,
+               db_scale_4bit_12db_max),
+WSS_DOUBLE_TLV("CD Playback Volume", 0,
+               CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 1, 1, 15, 1,
+               db_scale_4bit_12db_max),
+WSS_DOUBLE("Aux Playback Switch", 0,
+               OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE_TLV("Aux Playback Volume", 0,
+               OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1,
+               db_scale_4bit_12db_max),
+};
+
+static int __devinit snd_opti93x_mixer(struct snd_wss *chip)
+{
+       struct snd_card *card;
+       unsigned int idx;
+       struct snd_ctl_elem_id id1, id2;
+       int err;
+
+       if (snd_BUG_ON(!chip || !chip->pcm))
+               return -EINVAL;
+
+       card = chip->card;
+
+       strcpy(card->mixername, chip->pcm->name);
+
+       memset(&id1, 0, sizeof(id1));
+       memset(&id2, 0, sizeof(id2));
+       id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+       /* reassign AUX0 switch to CD */
+       strcpy(id1.name, "Aux Playback Switch");
+       strcpy(id2.name, "CD Playback Switch");
+       err = snd_ctl_rename_id(card, &id1, &id2);
+       if (err < 0) {
+               snd_printk(KERN_ERR "Cannot rename opti93x control\n");
+               return err;
+       }
+       /* reassign AUX1 switch to FM */
+       strcpy(id1.name, "Aux Playback Switch"); id1.index = 1;
+       strcpy(id2.name, "FM Playback Switch");
+       err = snd_ctl_rename_id(card, &id1, &id2);
+       if (err < 0) {
+               snd_printk(KERN_ERR "Cannot rename opti93x control\n");
+               return err;
+       }
+       /* remove AUX1 volume */
+       strcpy(id1.name, "Aux Playback Volume"); id1.index = 1;
+       snd_ctl_remove_id(card, &id1);
+
+       /* Replace WSS volume controls with OPTi93x volume controls */
+       id1.index = 0;
+       for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) {
+               strcpy(id1.name, snd_opti93x_controls[idx].name);
+               snd_ctl_remove_id(card, &id1);
+
+               err = snd_ctl_add(card,
+                               snd_ctl_new1(&snd_opti93x_controls[idx], chip));
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+
 static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id)
 {
        struct snd_opti9xx *chip = dev_id;
@@ -754,6 +842,11 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
        error = snd_wss_mixer(codec);
        if (error < 0)
                return error;
+#ifdef OPTi93X
+       error = snd_opti93x_mixer(codec);
+       if (error < 0)
+               return error;
+#endif
 #ifdef CS4231
        error = snd_wss_timer(codec, 0, &timer);
        if (error < 0)
index faeffceb01b796c86bbd339dfa940e507f024142..af36696817880fe9103641828b2b581060d507fe 100644 (file)
@@ -12,6 +12,7 @@ snd-sb16-objs := sb16.o
 snd-sbawe-objs := sbawe.o emu8000.o
 snd-emu8000-synth-objs := emu8000_synth.o emu8000_callback.o emu8000_patch.o emu8000_pcm.o
 snd-es968-objs := es968.o
+snd-jazz16-objs := jazz16.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_SB_COMMON) += snd-sb-common.o
@@ -21,6 +22,7 @@ obj-$(CONFIG_SND_SB8) += snd-sb8.o
 obj-$(CONFIG_SND_SB16) += snd-sb16.o
 obj-$(CONFIG_SND_SBAWE) += snd-sbawe.o
 obj-$(CONFIG_SND_ES968) += snd-es968.o
+obj-$(CONFIG_SND_JAZZ16) += snd-jazz16.o
 ifeq ($(CONFIG_SND_SB16_CSP),y)
   obj-$(CONFIG_SND_SB16) += snd-sb16-csp.o
   obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o
diff --git a/sound/isa/sb/jazz16.c b/sound/isa/sb/jazz16.c
new file mode 100644 (file)
index 0000000..8d21a3f
--- /dev/null
@@ -0,0 +1,404 @@
+
+/*
+ * jazz16.c - driver for Media Vision Jazz16 based soundcards.
+ * Copyright (C) 2009 Krzysztof Helt <krzysztof.h1@wp.pl>
+ * Based on patches posted by Rask Ingemann Lambertsen and Rene Herman.
+ * Based on OSS Sound Blaster driver.
+ *
+ * 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/module.h>
+#include <linux/io.h>
+#include <asm/dma.h>
+#include <linux/isa.h>
+#include <sound/core.h>
+#include <sound/mpu401.h>
+#include <sound/opl3.h>
+#include <sound/sb.h>
+#define SNDRV_LEGACY_FIND_FREE_IRQ
+#define SNDRV_LEGACY_FIND_FREE_DMA
+#include <sound/initval.h>
+
+#define PFX "jazz16: "
+
+MODULE_DESCRIPTION("Media Vision Jazz16");
+MODULE_SUPPORTED_DEVICE("{{Media Vision ??? },"
+               "{RTL,RTL3000}}");
+
+MODULE_AUTHOR("Krzysztof Helt <krzysztof.h1@wp.pl>");
+MODULE_LICENSE("GPL");
+
+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 unsigned long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static unsigned long mpu_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 dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
+static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for Media Vision Jazz16 based soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for Media Vision Jazz16 based soundcard.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable Media Vision Jazz16 based soundcard.");
+module_param_array(port, long, NULL, 0444);
+MODULE_PARM_DESC(port, "Port # for jazz16 driver.");
+module_param_array(mpu_port, long, NULL, 0444);
+MODULE_PARM_DESC(mpu_port, "MPU-401 port # for jazz16 driver.");
+module_param_array(irq, int, NULL, 0444);
+MODULE_PARM_DESC(irq, "IRQ # for jazz16 driver.");
+module_param_array(mpu_irq, int, NULL, 0444);
+MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for jazz16 driver.");
+module_param_array(dma8, int, NULL, 0444);
+MODULE_PARM_DESC(dma8, "DMA8 # for jazz16 driver.");
+module_param_array(dma16, int, NULL, 0444);
+MODULE_PARM_DESC(dma16, "DMA16 # for jazz16 driver.");
+
+#define SB_JAZZ16_WAKEUP       0xaf
+#define SB_JAZZ16_SET_PORTS    0x50
+#define SB_DSP_GET_JAZZ_BRD_REV        0xfa
+#define SB_JAZZ16_SET_DMAINTR  0xfb
+#define SB_DSP_GET_JAZZ_MODEL  0xfe
+
+struct snd_card_jazz16 {
+       struct snd_sb *chip;
+};
+
+static irqreturn_t jazz16_interrupt(int irq, void *chip)
+{
+       return snd_sb8dsp_interrupt(chip);
+}
+
+static int __devinit jazz16_configure_ports(unsigned long port,
+                                           unsigned long mpu_port, int idx)
+{
+       unsigned char val;
+
+       if (!request_region(0x201, 1, "jazz16 config")) {
+               snd_printk(KERN_ERR "config port region is already in use.\n");
+               return -EBUSY;
+       }
+       outb(SB_JAZZ16_WAKEUP - idx, 0x201);
+       udelay(100);
+       outb(SB_JAZZ16_SET_PORTS + idx, 0x201);
+       udelay(100);
+       val = port & 0x70;
+       val |= (mpu_port & 0x30) >> 4;
+       outb(val, 0x201);
+
+       release_region(0x201, 1);
+       return 0;
+}
+
+static int __devinit jazz16_detect_board(unsigned long port,
+                                        unsigned long mpu_port)
+{
+       int err;
+       int val;
+       struct snd_sb chip;
+
+       if (!request_region(port, 0x10, "jazz16")) {
+               snd_printk(KERN_ERR "I/O port region is already in use.\n");
+               return -EBUSY;
+       }
+       /* just to call snd_sbdsp_command/reset/get_byte() */
+       chip.port = port;
+
+       err = snd_sbdsp_reset(&chip);
+       if (err < 0)
+               for (val = 0; val < 4; val++) {
+                       err = jazz16_configure_ports(port, mpu_port, val);
+                       if (err < 0)
+                               break;
+
+                       err = snd_sbdsp_reset(&chip);
+                       if (!err)
+                               break;
+               }
+       if (err < 0) {
+               err = -ENODEV;
+               goto err_unmap;
+       }
+       if (!snd_sbdsp_command(&chip, SB_DSP_GET_JAZZ_BRD_REV)) {
+               err = -EBUSY;
+               goto err_unmap;
+       }
+       val = snd_sbdsp_get_byte(&chip);
+       if (val >= 0x30)
+               snd_sbdsp_get_byte(&chip);
+
+       if ((val & 0xf0) != 0x10) {
+               err = -ENODEV;
+               goto err_unmap;
+       }
+       if (!snd_sbdsp_command(&chip, SB_DSP_GET_JAZZ_MODEL)) {
+               err = -EBUSY;
+               goto err_unmap;
+       }
+       snd_sbdsp_get_byte(&chip);
+       err = snd_sbdsp_get_byte(&chip);
+       snd_printd("Media Vision Jazz16 board detected: rev 0x%x, model 0x%x\n",
+                  val, err);
+
+       err = 0;
+
+err_unmap:
+       release_region(port, 0x10);
+       return err;
+}
+
+static int __devinit jazz16_configure_board(struct snd_sb *chip, int mpu_irq)
+{
+       static unsigned char jazz_irq_bits[] = { 0, 0, 2, 3, 0, 1, 0, 4,
+                                                0, 2, 5, 0, 0, 0, 0, 6 };
+       static unsigned char jazz_dma_bits[] = { 0, 1, 0, 2, 0, 3, 0, 4 };
+
+       if (jazz_dma_bits[chip->dma8] == 0 ||
+           jazz_dma_bits[chip->dma16] == 0 ||
+           jazz_irq_bits[chip->irq] == 0)
+               return -EINVAL;
+
+       if (!snd_sbdsp_command(chip, SB_JAZZ16_SET_DMAINTR))
+               return -EBUSY;
+
+       if (!snd_sbdsp_command(chip,
+                              jazz_dma_bits[chip->dma8] |
+                              (jazz_dma_bits[chip->dma16] << 4)))
+               return -EBUSY;
+
+       if (!snd_sbdsp_command(chip,
+                              jazz_irq_bits[chip->irq] |
+                              (jazz_irq_bits[mpu_irq] << 4)))
+               return -EBUSY;
+
+       return 0;
+}
+
+static int __devinit snd_jazz16_match(struct device *devptr, unsigned int dev)
+{
+       if (!enable[dev])
+               return 0;
+       if (port[dev] == SNDRV_AUTO_PORT) {
+               snd_printk(KERN_ERR "please specify port\n");
+               return 0;
+       } else if (port[dev] == 0x200 || (port[dev] & ~0x270)) {
+               snd_printk(KERN_ERR "incorrect port specified\n");
+               return 0;
+       }
+       if (dma8[dev] != SNDRV_AUTO_DMA &&
+           dma8[dev] != 1 && dma8[dev] != 3) {
+               snd_printk(KERN_ERR "dma8 must be 1 or 3\n");
+               return 0;
+       }
+       if (dma16[dev] != SNDRV_AUTO_DMA &&
+           dma16[dev] != 5 && dma16[dev] != 7) {
+               snd_printk(KERN_ERR "dma16 must be 5 or 7\n");
+               return 0;
+       }
+       if (mpu_port[dev] != SNDRV_AUTO_PORT &&
+           (mpu_port[dev] & ~0x030) != 0x300) {
+               snd_printk(KERN_ERR "incorrect mpu_port specified\n");
+               return 0;
+       }
+       if (mpu_irq[dev] != SNDRV_AUTO_DMA &&
+           mpu_irq[dev] != 2 && mpu_irq[dev] != 3 &&
+           mpu_irq[dev] != 5 && mpu_irq[dev] != 7) {
+               snd_printk(KERN_ERR "mpu_irq must be 2, 3, 5 or 7\n");
+               return 0;
+       }
+       return 1;
+}
+
+static int __devinit snd_jazz16_probe(struct device *devptr, unsigned int dev)
+{
+       struct snd_card *card;
+       struct snd_card_jazz16 *jazz16;
+       struct snd_sb *chip;
+       struct snd_opl3 *opl3;
+       static int possible_irqs[] = {2, 3, 5, 7, 9, 10, 15, -1};
+       static int possible_dmas8[] = {1, 3, -1};
+       static int possible_dmas16[] = {5, 7, -1};
+       int err, xirq, xdma8, xdma16, xmpu_port, xmpu_irq;
+
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+                             sizeof(struct snd_card_jazz16), &card);
+       if (err < 0)
+               return err;
+
+       jazz16 = card->private_data;
+
+       xirq = irq[dev];
+       if (xirq == SNDRV_AUTO_IRQ) {
+               xirq = snd_legacy_find_free_irq(possible_irqs);
+               if (xirq < 0) {
+                       snd_printk(KERN_ERR "unable to find a free IRQ\n");
+                       err = -EBUSY;
+                       goto err_free;
+               }
+       }
+       xdma8 = dma8[dev];
+       if (xdma8 == SNDRV_AUTO_DMA) {
+               xdma8 = snd_legacy_find_free_dma(possible_dmas8);
+               if (xdma8 < 0) {
+                       snd_printk(KERN_ERR "unable to find a free DMA8\n");
+                       err = -EBUSY;
+                       goto err_free;
+               }
+       }
+       xdma16 = dma16[dev];
+       if (xdma16 == SNDRV_AUTO_DMA) {
+               xdma16 = snd_legacy_find_free_dma(possible_dmas16);
+               if (xdma16 < 0) {
+                       snd_printk(KERN_ERR "unable to find a free DMA16\n");
+                       err = -EBUSY;
+                       goto err_free;
+               }
+       }
+
+       xmpu_port = mpu_port[dev];
+       if (xmpu_port == SNDRV_AUTO_PORT)
+               xmpu_port = 0;
+       err = jazz16_detect_board(port[dev], xmpu_port);
+       if (err < 0) {
+               printk(KERN_ERR "Media Vision Jazz16 board not detected\n");
+               goto err_free;
+       }
+       err = snd_sbdsp_create(card, port[dev], irq[dev],
+                              jazz16_interrupt,
+                              dma8[dev], dma16[dev],
+                              SB_HW_JAZZ16,
+                              &chip);
+       if (err < 0)
+               goto err_free;
+
+       xmpu_irq = mpu_irq[dev];
+       if (xmpu_irq == SNDRV_AUTO_IRQ || mpu_port[dev] == SNDRV_AUTO_PORT)
+               xmpu_irq = 0;
+       err = jazz16_configure_board(chip, xmpu_irq);
+       if (err < 0) {
+               printk(KERN_ERR "Media Vision Jazz16 configuration failed\n");
+               goto err_free;
+       }
+
+       jazz16->chip = chip;
+
+       strcpy(card->driver, "jazz16");
+       strcpy(card->shortname, "Media Vision Jazz16");
+       sprintf(card->longname,
+               "Media Vision Jazz16 at 0x%lx, irq %d, dma8 %d, dma16 %d",
+               port[dev], xirq, xdma8, xdma16);
+
+       err = snd_sb8dsp_pcm(chip, 0, NULL);
+       if (err < 0)
+               goto err_free;
+       err = snd_sbmixer_new(chip);
+       if (err < 0)
+               goto err_free;
+
+       err = snd_opl3_create(card, chip->port, chip->port + 2,
+                             OPL3_HW_AUTO, 1, &opl3);
+       if (err < 0)
+               snd_printk(KERN_WARNING "no OPL device at 0x%lx-0x%lx\n",
+                          chip->port, chip->port + 2);
+       else {
+               err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
+               if (err < 0)
+                       goto err_free;
+       }
+       if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
+               if (mpu_irq[dev] == SNDRV_AUTO_IRQ)
+                       mpu_irq[dev] = -1;
+
+               if (snd_mpu401_uart_new(card, 0,
+                                       MPU401_HW_MPU401,
+                                       mpu_port[dev], 0,
+                                       mpu_irq[dev],
+                                       mpu_irq[dev] >= 0 ? IRQF_DISABLED : 0,
+                                       NULL) < 0)
+                       snd_printk(KERN_ERR "no MPU-401 device at 0x%lx\n",
+                                       mpu_port[dev]);
+       }
+
+       snd_card_set_dev(card, devptr);
+
+       err = snd_card_register(card);
+       if (err < 0)
+               goto err_free;
+
+       dev_set_drvdata(devptr, card);
+       return 0;
+
+err_free:
+       snd_card_free(card);
+       return err;
+}
+
+static int __devexit snd_jazz16_remove(struct device *devptr, unsigned int dev)
+{
+       struct snd_card *card = dev_get_drvdata(devptr);
+
+       dev_set_drvdata(devptr, NULL);
+       snd_card_free(card);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int snd_jazz16_suspend(struct device *pdev, unsigned int n,
+                              pm_message_t state)
+{
+       struct snd_card *card = dev_get_drvdata(pdev);
+       struct snd_card_jazz16 *acard = card->private_data;
+       struct snd_sb *chip = acard->chip;
+
+       snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+       snd_pcm_suspend_all(chip->pcm);
+       snd_sbmixer_suspend(chip);
+       return 0;
+}
+
+static int snd_jazz16_resume(struct device *pdev, unsigned int n)
+{
+       struct snd_card *card = dev_get_drvdata(pdev);
+       struct snd_card_jazz16 *acard = card->private_data;
+       struct snd_sb *chip = acard->chip;
+
+       snd_sbdsp_reset(chip);
+       snd_sbmixer_resume(chip);
+       snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+       return 0;
+}
+#endif
+
+static struct isa_driver snd_jazz16_driver = {
+       .match          = snd_jazz16_match,
+       .probe          = snd_jazz16_probe,
+       .remove         = __devexit_p(snd_jazz16_remove),
+#ifdef CONFIG_PM
+       .suspend        = snd_jazz16_suspend,
+       .resume         = snd_jazz16_resume,
+#endif
+       .driver         = {
+               .name   = "jazz16"
+       },
+};
+
+static int __init alsa_card_jazz16_init(void)
+{
+       return isa_register_driver(&snd_jazz16_driver, SNDRV_CARDS);
+}
+
+static void __exit alsa_card_jazz16_exit(void)
+{
+       isa_unregister_driver(&snd_jazz16_driver);
+}
+
+module_init(alsa_card_jazz16_init)
+module_exit(alsa_card_jazz16_exit)
index 658d55769c9cd5ff44adf13aee830b455b215f5f..7d84c9f34dc90cf491a001acf1bca64740ac9a3e 100644 (file)
@@ -106,9 +106,21 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream)
        struct snd_sb *chip = snd_pcm_substream_chip(substream);
        struct snd_pcm_runtime *runtime = substream->runtime;
        unsigned int mixreg, rate, size, count;
+       unsigned char format;
+       unsigned char stereo = runtime->channels > 1;
+       int dma;
 
        rate = runtime->rate;
        switch (chip->hardware) {
+       case SB_HW_JAZZ16:
+               if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) {
+                       if (chip->mode & SB_MODE_CAPTURE_16)
+                               return -EBUSY;
+                       else
+                               chip->mode |= SB_MODE_PLAYBACK_16;
+               }
+               chip->playback_format = SB_DSP_LO_OUTPUT_AUTO;
+               break;
        case SB_HW_PRO:
                if (runtime->channels > 1) {
                        if (snd_BUG_ON(rate != SB8_RATE(11025) &&
@@ -133,11 +145,21 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream)
        default:
                return -EINVAL;
        }
+       if (chip->mode & SB_MODE_PLAYBACK_16) {
+               format = stereo ? SB_DSP_STEREO_16BIT : SB_DSP_MONO_16BIT;
+               dma = chip->dma16;
+       } else {
+               format = stereo ? SB_DSP_STEREO_8BIT : SB_DSP_MONO_8BIT;
+               chip->mode |= SB_MODE_PLAYBACK_8;
+               dma = chip->dma8;
+       }
        size = chip->p_dma_size = snd_pcm_lib_buffer_bytes(substream);
        count = chip->p_period_size = snd_pcm_lib_period_bytes(substream);
        spin_lock_irqsave(&chip->reg_lock, flags);
        snd_sbdsp_command(chip, SB_DSP_SPEAKER_ON);
-       if (runtime->channels > 1) {
+       if (chip->hardware == SB_HW_JAZZ16)
+               snd_sbdsp_command(chip, format);
+       else if (stereo) {
                /* set playback stereo mode */
                spin_lock(&chip->mixer_lock);
                mixreg = snd_sbmixer_read(chip, SB_DSP_STEREO_SW);
@@ -147,15 +169,14 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream)
                /* Soundblaster hardware programming reference guide, 3-23 */
                snd_sbdsp_command(chip, SB_DSP_DMA8_EXIT);
                runtime->dma_area[0] = 0x80;
-               snd_dma_program(chip->dma8, runtime->dma_addr, 1, DMA_MODE_WRITE);
+               snd_dma_program(dma, runtime->dma_addr, 1, DMA_MODE_WRITE);
                /* force interrupt */
-               chip->mode = SB_MODE_HALT;
                snd_sbdsp_command(chip, SB_DSP_OUTPUT);
                snd_sbdsp_command(chip, 0);
                snd_sbdsp_command(chip, 0);
        }
        snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE);
-       if (runtime->channels > 1) {
+       if (stereo) {
                snd_sbdsp_command(chip, 256 - runtime->rate_den / 2);
                spin_lock(&chip->mixer_lock);
                /* save output filter status and turn it off */
@@ -168,13 +189,15 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream)
                snd_sbdsp_command(chip, 256 - runtime->rate_den);
        }
        if (chip->playback_format != SB_DSP_OUTPUT) {
+               if (chip->mode & SB_MODE_PLAYBACK_16)
+                       count /= 2;
                count--;
                snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE);
                snd_sbdsp_command(chip, count & 0xff);
                snd_sbdsp_command(chip, count >> 8);
        }
        spin_unlock_irqrestore(&chip->reg_lock, flags);
-       snd_dma_program(chip->dma8, runtime->dma_addr,
+       snd_dma_program(dma, runtime->dma_addr,
                        size, DMA_MODE_WRITE | DMA_AUTOINIT);
        return 0;
 }
@@ -212,7 +235,6 @@ static int snd_sb8_playback_trigger(struct snd_pcm_substream *substream,
                snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);
        }
        spin_unlock_irqrestore(&chip->reg_lock, flags);
-       chip->mode = (cmd == SNDRV_PCM_TRIGGER_START) ? SB_MODE_PLAYBACK_8 : SB_MODE_HALT;
        return 0;
 }
 
@@ -234,9 +256,21 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream)
        struct snd_sb *chip = snd_pcm_substream_chip(substream);
        struct snd_pcm_runtime *runtime = substream->runtime;
        unsigned int mixreg, rate, size, count;
+       unsigned char format;
+       unsigned char stereo = runtime->channels > 1;
+       int dma;
 
        rate = runtime->rate;
        switch (chip->hardware) {
+       case SB_HW_JAZZ16:
+               if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) {
+                       if (chip->mode & SB_MODE_PLAYBACK_16)
+                               return -EBUSY;
+                       else
+                               chip->mode |= SB_MODE_CAPTURE_16;
+               }
+               chip->capture_format = SB_DSP_LO_INPUT_AUTO;
+               break;
        case SB_HW_PRO:
                if (runtime->channels > 1) {
                        if (snd_BUG_ON(rate != SB8_RATE(11025) &&
@@ -262,14 +296,24 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream)
        default:
                return -EINVAL;
        }
+       if (chip->mode & SB_MODE_CAPTURE_16) {
+               format = stereo ? SB_DSP_STEREO_16BIT : SB_DSP_MONO_16BIT;
+               dma = chip->dma16;
+       } else {
+               format = stereo ? SB_DSP_STEREO_8BIT : SB_DSP_MONO_8BIT;
+               chip->mode |= SB_MODE_CAPTURE_8;
+               dma = chip->dma8;
+       }
        size = chip->c_dma_size = snd_pcm_lib_buffer_bytes(substream);
        count = chip->c_period_size = snd_pcm_lib_period_bytes(substream);
        spin_lock_irqsave(&chip->reg_lock, flags);
        snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);
-       if (runtime->channels > 1)
+       if (chip->hardware == SB_HW_JAZZ16)
+               snd_sbdsp_command(chip, format);
+       else if (stereo)
                snd_sbdsp_command(chip, SB_DSP_STEREO_8BIT);
        snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE);
-       if (runtime->channels > 1) {
+       if (stereo) {
                snd_sbdsp_command(chip, 256 - runtime->rate_den / 2);
                spin_lock(&chip->mixer_lock);
                /* save input filter status and turn it off */
@@ -282,13 +326,15 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream)
                snd_sbdsp_command(chip, 256 - runtime->rate_den);
        }
        if (chip->capture_format != SB_DSP_INPUT) {
+               if (chip->mode & SB_MODE_PLAYBACK_16)
+                       count /= 2;
                count--;
                snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE);
                snd_sbdsp_command(chip, count & 0xff);
                snd_sbdsp_command(chip, count >> 8);
        }
        spin_unlock_irqrestore(&chip->reg_lock, flags);
-       snd_dma_program(chip->dma8, runtime->dma_addr,
+       snd_dma_program(dma, runtime->dma_addr,
                        size, DMA_MODE_READ | DMA_AUTOINIT);
        return 0;
 }
@@ -328,7 +374,6 @@ static int snd_sb8_capture_trigger(struct snd_pcm_substream *substream,
                snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);
        }
        spin_unlock_irqrestore(&chip->reg_lock, flags);
-       chip->mode = (cmd == SNDRV_PCM_TRIGGER_START) ? SB_MODE_CAPTURE_8 : SB_MODE_HALT;
        return 0;
 }
 
@@ -339,13 +384,21 @@ irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip)
 
        snd_sb_ack_8bit(chip);
        switch (chip->mode) {
-       case SB_MODE_PLAYBACK_8:        /* ok.. playback is active */
+       case SB_MODE_PLAYBACK_16:       /* ok.. playback is active */
+               if (chip->hardware != SB_HW_JAZZ16)
+                       break;
+               /* fallthru */
+       case SB_MODE_PLAYBACK_8:
                substream = chip->playback_substream;
                runtime = substream->runtime;
                if (chip->playback_format == SB_DSP_OUTPUT)
                        snd_sb8_playback_trigger(substream, SNDRV_PCM_TRIGGER_START);
                snd_pcm_period_elapsed(substream);
                break;
+       case SB_MODE_CAPTURE_16:
+               if (chip->hardware != SB_HW_JAZZ16)
+                       break;
+               /* fallthru */
        case SB_MODE_CAPTURE_8:
                substream = chip->capture_substream;
                runtime = substream->runtime;
@@ -361,10 +414,15 @@ static snd_pcm_uframes_t snd_sb8_playback_pointer(struct snd_pcm_substream *subs
 {
        struct snd_sb *chip = snd_pcm_substream_chip(substream);
        size_t ptr;
+       int dma;
 
-       if (chip->mode != SB_MODE_PLAYBACK_8)
+       if (chip->mode & SB_MODE_PLAYBACK_8)
+               dma = chip->dma8;
+       else if (chip->mode & SB_MODE_PLAYBACK_16)
+               dma = chip->dma16;
+       else
                return 0;
-       ptr = snd_dma_pointer(chip->dma8, chip->p_dma_size);
+       ptr = snd_dma_pointer(dma, chip->p_dma_size);
        return bytes_to_frames(substream->runtime, ptr);
 }
 
@@ -372,10 +430,15 @@ static snd_pcm_uframes_t snd_sb8_capture_pointer(struct snd_pcm_substream *subst
 {
        struct snd_sb *chip = snd_pcm_substream_chip(substream);
        size_t ptr;
+       int dma;
 
-       if (chip->mode != SB_MODE_CAPTURE_8)
+       if (chip->mode & SB_MODE_CAPTURE_8)
+               dma = chip->dma8;
+       else if (chip->mode & SB_MODE_CAPTURE_16)
+               dma = chip->dma16;
+       else
                return 0;
-       ptr = snd_dma_pointer(chip->dma8, chip->c_dma_size);
+       ptr = snd_dma_pointer(dma, chip->c_dma_size);
        return bytes_to_frames(substream->runtime, ptr);
 }
 
@@ -446,6 +509,14 @@ static int snd_sb8_open(struct snd_pcm_substream *substream)
                runtime->hw = snd_sb8_capture;
        }
        switch (chip->hardware) {
+       case SB_HW_JAZZ16:
+               if (chip->dma16 == 5 || chip->dma16 == 7)
+                       runtime->hw.formats |= SNDRV_PCM_FMTBIT_S16_LE;
+               runtime->hw.rates |= SNDRV_PCM_RATE_8000_48000;
+               runtime->hw.rate_min = 4000;
+               runtime->hw.rate_max = 50000;
+               runtime->hw.channels_max = 2;
+               break;
        case SB_HW_PRO:
                runtime->hw.rate_max = 44100;
                runtime->hw.channels_max = 2;
@@ -468,6 +539,14 @@ static int snd_sb8_open(struct snd_pcm_substream *substream)
        }
        snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
                                      &hw_constraints_clock);
+       if (chip->dma8 > 3 || chip->dma16 >= 0) {
+               snd_pcm_hw_constraint_step(runtime, 0,
+                                          SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 2);
+               snd_pcm_hw_constraint_step(runtime, 0,
+                                          SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 2);
+               runtime->hw.buffer_bytes_max = 128 * 1024 * 1024;
+               runtime->hw.period_bytes_max = 128 * 1024 * 1024;
+       }
        return 0;       
 }
 
@@ -480,6 +559,10 @@ static int snd_sb8_close(struct snd_pcm_substream *substream)
        chip->capture_substream = NULL;
        spin_lock_irqsave(&chip->open_lock, flags);
        chip->open &= ~SB_OPEN_PCM;
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               chip->mode &= ~SB_MODE_PLAYBACK;
+       else
+               chip->mode &= ~SB_MODE_CAPTURE;
        spin_unlock_irqrestore(&chip->open_lock, flags);
        return 0;
 }
@@ -515,6 +598,7 @@ int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm)
        struct snd_card *card = chip->card;
        struct snd_pcm *pcm;
        int err;
+       size_t max_prealloc = 64 * 1024;
 
        if (rpcm)
                *rpcm = NULL;
@@ -527,9 +611,11 @@ int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm)
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb8_playback_ops);
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb8_capture_ops);
 
+       if (chip->dma8 > 3 || chip->dma16 >= 0)
+               max_prealloc = 128 * 1024;
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                                              snd_dma_isa_data(),
-                                             64*1024, 64*1024);
+                                             64*1024, max_prealloc);
 
        if (rpcm)
                *rpcm = pcm;
index 27a65150225168a3f7264c4d6c1c6f8667cc7bfa..eae6c1c0eff9bc536d87f8fb3eb2b7abb578a7e1 100644 (file)
@@ -170,6 +170,9 @@ static int snd_sbdsp_probe(struct snd_sb * chip)
        case SB_HW_CS5530:
                str = "16 (CS5530)";
                break;
+       case SB_HW_JAZZ16:
+               str = "Pro (Jazz16)";
+               break;
        default:
                return -ENODEV;
        }
index 318ff0c823e75cfb869d42798502b030269f2faf..6496822c1808b53c172d56df4382fb88e9e20e95 100644 (file)
@@ -528,20 +528,11 @@ int snd_sbmixer_add_ctl(struct snd_sb *chip, const char *name, int index, int ty
  * SB 2.0 specific mixer elements
  */
 
-static struct sbmix_elem snd_sb20_ctl_master_play_vol =
-       SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7);
-static struct sbmix_elem snd_sb20_ctl_pcm_play_vol =
-       SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3);
-static struct sbmix_elem snd_sb20_ctl_synth_play_vol =
-       SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7);
-static struct sbmix_elem snd_sb20_ctl_cd_play_vol =
-       SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7);
-
-static struct sbmix_elem *snd_sb20_controls[] = {
-       &snd_sb20_ctl_master_play_vol,
-       &snd_sb20_ctl_pcm_play_vol,
-       &snd_sb20_ctl_synth_play_vol,
-       &snd_sb20_ctl_cd_play_vol
+static struct sbmix_elem snd_sb20_controls[] = {
+       SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7),
+       SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3),
+       SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7),
+       SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7)
 };
 
 static unsigned char snd_sb20_init_values[][2] = {
@@ -552,41 +543,24 @@ static unsigned char snd_sb20_init_values[][2] = {
 /*
  * SB Pro specific mixer elements
  */
-static struct sbmix_elem snd_sbpro_ctl_master_play_vol =
-       SB_DOUBLE("Master Playback Volume", SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7);
-static struct sbmix_elem snd_sbpro_ctl_pcm_play_vol =
-       SB_DOUBLE("PCM Playback Volume", SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7);
-static struct sbmix_elem snd_sbpro_ctl_pcm_play_filter =
-       SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1);
-static struct sbmix_elem snd_sbpro_ctl_synth_play_vol =
-       SB_DOUBLE("Synth Playback Volume", SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7);
-static struct sbmix_elem snd_sbpro_ctl_cd_play_vol =
-       SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7);
-static struct sbmix_elem snd_sbpro_ctl_line_play_vol =
-       SB_DOUBLE("Line Playback Volume", SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7);
-static struct sbmix_elem snd_sbpro_ctl_mic_play_vol =
-       SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3);
-static struct sbmix_elem snd_sbpro_ctl_capture_source =
+static struct sbmix_elem snd_sbpro_controls[] = {
+       SB_DOUBLE("Master Playback Volume",
+                 SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7),
+       SB_DOUBLE("PCM Playback Volume",
+                 SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7),
+       SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1),
+       SB_DOUBLE("Synth Playback Volume",
+                 SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7),
+       SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7),
+       SB_DOUBLE("Line Playback Volume",
+                 SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7),
+       SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3),
        {
                .name = "Capture Source",
                .type = SB_MIX_CAPTURE_PRO
-       };
-static struct sbmix_elem snd_sbpro_ctl_capture_filter =
-       SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1);
-static struct sbmix_elem snd_sbpro_ctl_capture_low_filter =
-       SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1);
-
-static struct sbmix_elem *snd_sbpro_controls[] = {
-       &snd_sbpro_ctl_master_play_vol,
-       &snd_sbpro_ctl_pcm_play_vol,
-       &snd_sbpro_ctl_pcm_play_filter,
-       &snd_sbpro_ctl_synth_play_vol,
-       &snd_sbpro_ctl_cd_play_vol,
-       &snd_sbpro_ctl_line_play_vol,
-       &snd_sbpro_ctl_mic_play_vol,
-       &snd_sbpro_ctl_capture_source,
-       &snd_sbpro_ctl_capture_filter,
-       &snd_sbpro_ctl_capture_low_filter
+       },
+       SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1),
+       SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1)
 };
 
 static unsigned char snd_sbpro_init_values[][2] = {
@@ -598,68 +572,42 @@ static unsigned char snd_sbpro_init_values[][2] = {
 /*
  * SB16 specific mixer elements
  */
-static struct sbmix_elem snd_sb16_ctl_master_play_vol =
-       SB_DOUBLE("Master Playback Volume", SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31);
-static struct sbmix_elem snd_sb16_ctl_3d_enhance_switch =
-       SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1);
-static struct sbmix_elem snd_sb16_ctl_tone_bass =
-       SB_DOUBLE("Tone Control - Bass", SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15);
-static struct sbmix_elem snd_sb16_ctl_tone_treble =
-       SB_DOUBLE("Tone Control - Treble", SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15);
-static struct sbmix_elem snd_sb16_ctl_pcm_play_vol =
-       SB_DOUBLE("PCM Playback Volume", SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31);
-static struct sbmix_elem snd_sb16_ctl_synth_capture_route =
-       SB16_INPUT_SW("Synth Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5);
-static struct sbmix_elem snd_sb16_ctl_synth_play_vol =
-       SB_DOUBLE("Synth Playback Volume", SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31);
-static struct sbmix_elem snd_sb16_ctl_cd_capture_route =
-       SB16_INPUT_SW("CD Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1);
-static struct sbmix_elem snd_sb16_ctl_cd_play_switch =
-       SB_DOUBLE("CD Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1);
-static struct sbmix_elem snd_sb16_ctl_cd_play_vol =
-       SB_DOUBLE("CD Playback Volume", SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31);
-static struct sbmix_elem snd_sb16_ctl_line_capture_route =
-       SB16_INPUT_SW("Line Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3);
-static struct sbmix_elem snd_sb16_ctl_line_play_switch =
-       SB_DOUBLE("Line Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1);
-static struct sbmix_elem snd_sb16_ctl_line_play_vol =
-       SB_DOUBLE("Line Playback Volume", SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31);
-static struct sbmix_elem snd_sb16_ctl_mic_capture_route =
-       SB16_INPUT_SW("Mic Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0);
-static struct sbmix_elem snd_sb16_ctl_mic_play_switch =
-       SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1);
-static struct sbmix_elem snd_sb16_ctl_mic_play_vol =
-       SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31);
-static struct sbmix_elem snd_sb16_ctl_pc_speaker_vol =
-       SB_SINGLE("Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3);
-static struct sbmix_elem snd_sb16_ctl_capture_vol =
-       SB_DOUBLE("Capture Volume", SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3);
-static struct sbmix_elem snd_sb16_ctl_play_vol =
-       SB_DOUBLE("Playback Volume", SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3);
-static struct sbmix_elem snd_sb16_ctl_auto_mic_gain =
-       SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1);
-
-static struct sbmix_elem *snd_sb16_controls[] = {
-       &snd_sb16_ctl_master_play_vol,
-       &snd_sb16_ctl_3d_enhance_switch,
-       &snd_sb16_ctl_tone_bass,
-       &snd_sb16_ctl_tone_treble,
-       &snd_sb16_ctl_pcm_play_vol,
-       &snd_sb16_ctl_synth_capture_route,
-       &snd_sb16_ctl_synth_play_vol,
-       &snd_sb16_ctl_cd_capture_route,
-       &snd_sb16_ctl_cd_play_switch,
-       &snd_sb16_ctl_cd_play_vol,
-       &snd_sb16_ctl_line_capture_route,
-       &snd_sb16_ctl_line_play_switch,
-       &snd_sb16_ctl_line_play_vol,
-       &snd_sb16_ctl_mic_capture_route,
-       &snd_sb16_ctl_mic_play_switch,
-       &snd_sb16_ctl_mic_play_vol,
-       &snd_sb16_ctl_pc_speaker_vol,
-       &snd_sb16_ctl_capture_vol,
-       &snd_sb16_ctl_play_vol,
-       &snd_sb16_ctl_auto_mic_gain
+static struct sbmix_elem snd_sb16_controls[] = {
+       SB_DOUBLE("Master Playback Volume",
+                 SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31),
+       SB_DOUBLE("PCM Playback Volume",
+                 SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31),
+       SB16_INPUT_SW("Synth Capture Route",
+                     SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5),
+       SB_DOUBLE("Synth Playback Volume",
+                 SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31),
+       SB16_INPUT_SW("CD Capture Route",
+                     SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1),
+       SB_DOUBLE("CD Playback Switch",
+                 SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1),
+       SB_DOUBLE("CD Playback Volume",
+                 SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31),
+       SB16_INPUT_SW("Mic Capture Route",
+                     SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0),
+       SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1),
+       SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31),
+       SB_SINGLE("Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3),
+       SB_DOUBLE("Capture Volume",
+                 SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3),
+       SB_DOUBLE("Playback Volume",
+                 SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3),
+       SB16_INPUT_SW("Line Capture Route",
+                     SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3),
+       SB_DOUBLE("Line Playback Switch",
+                 SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1),
+       SB_DOUBLE("Line Playback Volume",
+                 SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31),
+       SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1),
+       SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1),
+       SB_DOUBLE("Tone Control - Bass",
+                 SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15),
+       SB_DOUBLE("Tone Control - Treble",
+                 SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15)
 };
 
 static unsigned char snd_sb16_init_values[][2] = {
@@ -678,46 +626,34 @@ static unsigned char snd_sb16_init_values[][2] = {
 /*
  * DT019x specific mixer elements
  */
-static struct sbmix_elem snd_dt019x_ctl_master_play_vol =
-       SB_DOUBLE("Master Playback Volume", SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4,0, 15);
-static struct sbmix_elem snd_dt019x_ctl_pcm_play_vol =
-       SB_DOUBLE("PCM Playback Volume", SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4,0, 15);
-static struct sbmix_elem snd_dt019x_ctl_synth_play_vol =
-       SB_DOUBLE("Synth Playback Volume", SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4,0, 15);
-static struct sbmix_elem snd_dt019x_ctl_cd_play_vol =
-       SB_DOUBLE("CD Playback Volume", SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4,0, 15);
-static struct sbmix_elem snd_dt019x_ctl_mic_play_vol =
-       SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7);
-static struct sbmix_elem snd_dt019x_ctl_pc_speaker_vol =
-       SB_SINGLE("Beep Volume", SB_DT019X_SPKR_DEV, 0,  7);
-static struct sbmix_elem snd_dt019x_ctl_line_play_vol =
-       SB_DOUBLE("Line Playback Volume", SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4,0, 15);
-static struct sbmix_elem snd_dt019x_ctl_pcm_play_switch =
-       SB_DOUBLE("PCM Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2,1, 1);
-static struct sbmix_elem snd_dt019x_ctl_synth_play_switch =
-       SB_DOUBLE("Synth Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4,3, 1);
-static struct sbmix_elem snd_dt019x_ctl_capture_source =
+static struct sbmix_elem snd_dt019x_controls[] = {
+       /* ALS4000 below has some parts which we might be lacking,
+        * e.g. snd_als4000_ctl_mono_playback_switch - check it! */
+       SB_DOUBLE("Master Playback Volume",
+                 SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4, 0, 15),
+       SB_DOUBLE("PCM Playback Switch",
+                 SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1),
+       SB_DOUBLE("PCM Playback Volume",
+                 SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4, 0, 15),
+       SB_DOUBLE("Synth Playback Switch",
+                 SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1),
+       SB_DOUBLE("Synth Playback Volume",
+                 SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4, 0, 15),
+       SB_DOUBLE("CD Playback Switch",
+                 SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1),
+       SB_DOUBLE("CD Playback Volume",
+                 SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4, 0, 15),
+       SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1),
+       SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7),
+       SB_SINGLE("Beep Volume", SB_DT019X_SPKR_DEV, 0,  7),
+       SB_DOUBLE("Line Playback Switch",
+                 SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1),
+       SB_DOUBLE("Line Playback Volume",
+                 SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4, 0, 15),
        {
                .name = "Capture Source",
                .type = SB_MIX_CAPTURE_DT019X
-       };
-
-static struct sbmix_elem *snd_dt019x_controls[] = {
-       /* ALS4000 below has some parts which we might be lacking,
-        * e.g. snd_als4000_ctl_mono_playback_switch - check it! */
-       &snd_dt019x_ctl_master_play_vol,
-       &snd_dt019x_ctl_pcm_play_vol,
-       &snd_dt019x_ctl_synth_play_vol,
-       &snd_dt019x_ctl_cd_play_vol,
-       &snd_dt019x_ctl_mic_play_vol,
-       &snd_dt019x_ctl_pc_speaker_vol,
-       &snd_dt019x_ctl_line_play_vol,
-       &snd_sb16_ctl_mic_play_switch,
-       &snd_sb16_ctl_cd_play_switch,
-       &snd_sb16_ctl_line_play_switch,
-       &snd_dt019x_ctl_pcm_play_switch,
-       &snd_dt019x_ctl_synth_play_switch,
-       &snd_dt019x_ctl_capture_source
+       }
 };
 
 static unsigned char snd_dt019x_init_values[][2] = {
@@ -735,82 +671,37 @@ static unsigned char snd_dt019x_init_values[][2] = {
 /*
  * ALS4000 specific mixer elements
  */
-static struct sbmix_elem snd_als4000_ctl_master_mono_playback_switch =
-       SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1);
-static struct sbmix_elem snd_als4k_ctl_master_mono_capture_route = {
+static struct sbmix_elem snd_als4000_controls[] = {
+       SB_DOUBLE("PCM Playback Switch",
+                 SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1),
+       SB_DOUBLE("Synth Playback Switch",
+                 SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1),
+       SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03),
+       SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1),
+       {
                .name = "Master Mono Capture Route",
                .type = SB_MIX_MONO_CAPTURE_ALS4K
-       };
-static struct sbmix_elem snd_als4000_ctl_mono_playback_switch =
-       SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2, 0, 1);
-static struct sbmix_elem snd_als4000_ctl_mic_20db_boost =
-       SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03);
-static struct sbmix_elem snd_als4000_ctl_mixer_analog_loopback =
-       SB_SINGLE("Analog Loopback Switch", SB_ALS4000_MIC_IN_GAIN, 7, 0x01);
-static struct sbmix_elem snd_als4000_ctl_mixer_digital_loopback =
+       },
+       SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2, 0, 1),
+       SB_SINGLE("Analog Loopback Switch", SB_ALS4000_MIC_IN_GAIN, 7, 0x01),
+       SB_SINGLE("3D Control - Switch", SB_ALS4000_3D_SND_FX, 6, 0x01),
        SB_SINGLE("Digital Loopback Switch",
-                 SB_ALS4000_CR3_CONFIGURATION, 7, 0x01);
-/* FIXME: functionality of 3D controls might be swapped, I didn't find
- * a description of how to identify what is supposed to be what */
-static struct sbmix_elem snd_als4000_3d_control_switch =
-       SB_SINGLE("3D Control - Switch", SB_ALS4000_3D_SND_FX, 6, 0x01);
-static struct sbmix_elem snd_als4000_3d_control_ratio =
-       SB_SINGLE("3D Control - Level", SB_ALS4000_3D_SND_FX, 0, 0x07);
-static struct sbmix_elem snd_als4000_3d_control_freq =
+                 SB_ALS4000_CR3_CONFIGURATION, 7, 0x01),
+       /* FIXME: functionality of 3D controls might be swapped, I didn't find
+        * a description of how to identify what is supposed to be what */
+       SB_SINGLE("3D Control - Level", SB_ALS4000_3D_SND_FX, 0, 0x07),
        /* FIXME: maybe there's actually some standard 3D ctrl name for it?? */
-       SB_SINGLE("3D Control - Freq", SB_ALS4000_3D_SND_FX, 4, 0x03);
-static struct sbmix_elem snd_als4000_3d_control_delay =
+       SB_SINGLE("3D Control - Freq", SB_ALS4000_3D_SND_FX, 4, 0x03),
        /* FIXME: ALS4000a.pdf mentions BBD (Bucket Brigade Device) time delay,
         * but what ALSA 3D attribute is that actually? "Center", "Depth",
         * "Wide" or "Space" or even "Level"? Assuming "Wide" for now... */
-       SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f);
-static struct sbmix_elem snd_als4000_3d_control_poweroff_switch =
-       SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01);
-static struct sbmix_elem snd_als4000_ctl_3db_freq_control_switch =
+       SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f),
+       SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01),
        SB_SINGLE("Master Playback 8kHz / 20kHz LPF Switch",
-                 SB_ALS4000_FMDAC, 5, 0x01);
+                 SB_ALS4000_FMDAC, 5, 0x01),
 #ifdef NOT_AVAILABLE
-static struct sbmix_elem snd_als4000_ctl_fmdac =
-       SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01);
-static struct sbmix_elem snd_als4000_ctl_qsound =
-       SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f);
-#endif
-
-static struct sbmix_elem *snd_als4000_controls[] = {
-                                               /* ALS4000a.PDF regs page */
-       &snd_sb16_ctl_master_play_vol,          /* MX30/31 12 */
-       &snd_dt019x_ctl_pcm_play_switch,        /* MX4C    16 */
-       &snd_sb16_ctl_pcm_play_vol,             /* MX32/33 12 */
-       &snd_sb16_ctl_synth_capture_route,      /* MX3D/3E 14 */
-       &snd_dt019x_ctl_synth_play_switch,      /* MX4C    16 */
-       &snd_sb16_ctl_synth_play_vol,           /* MX34/35 12/13 */
-       &snd_sb16_ctl_cd_capture_route,         /* MX3D/3E 14 */
-       &snd_sb16_ctl_cd_play_switch,           /* MX3C    14 */
-       &snd_sb16_ctl_cd_play_vol,              /* MX36/37 13 */
-       &snd_sb16_ctl_line_capture_route,       /* MX3D/3E 14 */
-       &snd_sb16_ctl_line_play_switch,         /* MX3C    14 */
-       &snd_sb16_ctl_line_play_vol,            /* MX38/39 13 */
-       &snd_sb16_ctl_mic_capture_route,        /* MX3D/3E 14 */
-       &snd_als4000_ctl_mic_20db_boost,        /* MX4D    16 */
-       &snd_sb16_ctl_mic_play_switch,          /* MX3C    14 */
-       &snd_sb16_ctl_mic_play_vol,             /* MX3A    13 */
-       &snd_sb16_ctl_pc_speaker_vol,           /* MX3B    14 */
-       &snd_sb16_ctl_capture_vol,              /* MX3F/40 15 */
-       &snd_sb16_ctl_play_vol,                 /* MX41/42 15 */
-       &snd_als4000_ctl_master_mono_playback_switch, /* MX4C 16 */
-       &snd_als4k_ctl_master_mono_capture_route, /* MX4B  16 */
-       &snd_als4000_ctl_mono_playback_switch,  /* MX4C    16 */
-       &snd_als4000_ctl_mixer_analog_loopback, /* MX4D    16 */
-       &snd_als4000_ctl_mixer_digital_loopback, /* CR3    21 */
-       &snd_als4000_3d_control_switch,          /* MX50   17 */
-       &snd_als4000_3d_control_ratio,           /* MX50   17 */
-       &snd_als4000_3d_control_freq,            /* MX50   17 */
-       &snd_als4000_3d_control_delay,           /* MX51   18 */
-       &snd_als4000_3d_control_poweroff_switch,        /* MX51    18 */
-       &snd_als4000_ctl_3db_freq_control_switch,       /* MX4F    17 */
-#ifdef NOT_AVAILABLE
-       &snd_als4000_ctl_fmdac,
-       &snd_als4000_ctl_qsound,
+       SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01),
+       SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f),
 #endif
 };
 
@@ -829,11 +720,10 @@ static unsigned char snd_als4000_init_values[][2] = {
        { SB_ALS4000_MIC_IN_GAIN, 0 },
 };
 
-
 /*
  */
 static int snd_sbmixer_init(struct snd_sb *chip,
-                           struct sbmix_elem **controls,
+                           struct sbmix_elem *controls,
                            int controls_count,
                            unsigned char map[][2],
                            int map_count,
@@ -856,7 +746,8 @@ static int snd_sbmixer_init(struct snd_sb *chip,
        }
 
        for (idx = 0; idx < controls_count; idx++) {
-               if ((err = snd_sbmixer_add_ctl_elem(chip, controls[idx])) < 0)
+               err = snd_sbmixer_add_ctl_elem(chip, &controls[idx]);
+               if (err < 0)
                        return err;
        }
        snd_component_add(card, name);
@@ -888,6 +779,7 @@ int snd_sbmixer_new(struct snd_sb *chip)
                        return err;
                break;
        case SB_HW_PRO:
+       case SB_HW_JAZZ16:
                if ((err = snd_sbmixer_init(chip,
                                            snd_sbpro_controls,
                                            ARRAY_SIZE(snd_sbpro_controls),
@@ -908,6 +800,15 @@ int snd_sbmixer_new(struct snd_sb *chip)
                        return err;
                break;
        case SB_HW_ALS4000:
+               /* use only the first 16 controls from SB16 */
+               err = snd_sbmixer_init(chip,
+                                       snd_sb16_controls,
+                                       16,
+                                       snd_sb16_init_values,
+                                       ARRAY_SIZE(snd_sb16_init_values),
+                                       "ALS4000");
+               if (err < 0)
+                       return err;
                if ((err = snd_sbmixer_init(chip,
                                            snd_als4000_controls,
                                            ARRAY_SIZE(snd_als4000_controls),
@@ -1029,6 +930,7 @@ void snd_sbmixer_suspend(struct snd_sb *chip)
                save_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs));
                break;
        case SB_HW_PRO:
+       case SB_HW_JAZZ16:
                save_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs));
                break;
        case SB_HW_16:
@@ -1055,6 +957,7 @@ void snd_sbmixer_resume(struct snd_sb *chip)
                restore_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs));
                break;
        case SB_HW_PRO:
+       case SB_HW_JAZZ16:
                restore_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs));
                break;
        case SB_HW_16:
index 5b9d6c18bc45a0479d1374480d64a47151b4801c..9191b32d913002fca98baea6b6945ab559156d54 100644 (file)
@@ -2014,6 +2014,7 @@ static int snd_wss_info_mux(struct snd_kcontrol *kcontrol,
        case WSS_HW_INTERWAVE:
                ptexts = gusmax_texts;
                break;
+       case WSS_HW_OPTI93X:
        case WSS_HW_OPL3SA2:
                ptexts = opl3sa_texts;
                break;
@@ -2246,54 +2247,12 @@ WSS_SINGLE("Beep Bypass Playback Switch", 0,
                CS4231_MONO_CTRL, 5, 1, 0),
 };
 
-static struct snd_kcontrol_new snd_opti93x_controls[] = {
-WSS_DOUBLE("Master Playback Switch", 0,
-               OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1),
-WSS_DOUBLE_TLV("Master Playback Volume", 0,
-               OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1,
-               db_scale_6bit),
-WSS_DOUBLE("PCM Playback Switch", 0,
-               CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
-WSS_DOUBLE("PCM Playback Volume", 0,
-               CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 31, 1),
-WSS_DOUBLE("FM Playback Switch", 0,
-               CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
-WSS_DOUBLE("FM Playback Volume", 0,
-               CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 1, 1, 15, 1),
-WSS_DOUBLE("Line Playback Switch", 0,
-               CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
-WSS_DOUBLE("Line Playback Volume", 0,
-               CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 15, 1),
-WSS_DOUBLE("Mic Playback Switch", 0,
-               OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1),
-WSS_DOUBLE("Mic Playback Volume", 0,
-               OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1),
-WSS_DOUBLE("Mic Boost", 0,
-               CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0),
-WSS_DOUBLE("CD Playback Switch", 0,
-               CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
-WSS_DOUBLE("CD Playback Volume", 0,
-               CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 1, 1, 15, 1),
-WSS_DOUBLE("Aux Playback Switch", 0,
-               OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1),
-WSS_DOUBLE("Aux Playback Volume", 0,
-               OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1),
-WSS_DOUBLE("Capture Volume", 0,
-               CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0),
-{
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Capture Source",
-       .info = snd_wss_info_mux,
-       .get = snd_wss_get_mux,
-       .put = snd_wss_put_mux,
-}
-};
-
 int snd_wss_mixer(struct snd_wss *chip)
 {
        struct snd_card *card;
        unsigned int idx;
        int err;
+       int count = ARRAY_SIZE(snd_wss_controls);
 
        if (snd_BUG_ON(!chip || !chip->pcm))
                return -EINVAL;
@@ -2302,28 +2261,19 @@ int snd_wss_mixer(struct snd_wss *chip)
 
        strcpy(card->mixername, chip->pcm->name);
 
-       if (chip->hardware == WSS_HW_OPTI93X)
-               for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) {
-                       err = snd_ctl_add(card,
-                                       snd_ctl_new1(&snd_opti93x_controls[idx],
-                                                    chip));
-                       if (err < 0)
-                               return err;
-               }
-       else {
-               int count = ARRAY_SIZE(snd_wss_controls);
-
-               /* Use only the first 11 entries on AD1848 */
-               if (chip->hardware & WSS_HW_AD1848_MASK)
-                       count = 11;
-
-               for (idx = 0; idx < count; idx++) {
-                       err = snd_ctl_add(card,
-                                       snd_ctl_new1(&snd_wss_controls[idx],
-                                                    chip));
-                       if (err < 0)
-                               return err;
-               }
+       /* Use only the first 11 entries on AD1848 */
+       if (chip->hardware & WSS_HW_AD1848_MASK)
+               count = 11;
+       /* There is no loopback on OPTI93X */
+       else if (chip->hardware == WSS_HW_OPTI93X)
+               count = 9;
+
+       for (idx = 0; idx < count; idx++) {
+               err = snd_ctl_add(card,
+                               snd_ctl_new1(&snd_wss_controls[idx],
+                                            chip));
+               if (err < 0)
+                       return err;
        }
        return 0;
 }
index f1d9d16b54864258ce47868556f4b2f5888909f7..6aff217379d910d2a333bec3c4c950a8ffe593d3 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 #include <linux/gfp.h>
-#include <linux/vmalloc.h>
 #include <linux/interrupt.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
@@ -603,25 +602,14 @@ static int snd_sgio2audio_pcm_close(struct snd_pcm_substream *substream)
 static int snd_sgio2audio_pcm_hw_params(struct snd_pcm_substream *substream,
                                        struct snd_pcm_hw_params *hw_params)
 {
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       int size = params_buffer_bytes(hw_params);
-
-       /* alloc virtual 'dma' area */
-       if (runtime->dma_area)
-               vfree(runtime->dma_area);
-       runtime->dma_area = vmalloc_user(size);
-       if (runtime->dma_area == NULL)
-               return -ENOMEM;
-       runtime->dma_bytes = size;
-       return 0;
+       return snd_pcm_lib_alloc_vmalloc_buffer(substream,
+                                               params_buffer_bytes(hw_params));
 }
 
 /* hw_free callback */
 static int snd_sgio2audio_pcm_hw_free(struct snd_pcm_substream *substream)
 {
-       vfree(substream->runtime->dma_area);
-       substream->runtime->dma_area = NULL;
-       return 0;
+       return snd_pcm_lib_free_vmalloc_buffer(substream);
 }
 
 /* prepare callback */
@@ -692,13 +680,6 @@ snd_sgio2audio_pcm_pointer(struct snd_pcm_substream *substream)
                               chip->channel[chan->idx].pos);
 }
 
-/* get the physical page pointer on the given offset */
-static struct page *snd_sgio2audio_page(struct snd_pcm_substream *substream,
-                                       unsigned long offset)
-{
-       return vmalloc_to_page(substream->runtime->dma_area + offset);
-}
-
 /* operators */
 static struct snd_pcm_ops snd_sgio2audio_playback1_ops = {
        .open =        snd_sgio2audio_playback1_open,
@@ -709,7 +690,8 @@ static struct snd_pcm_ops snd_sgio2audio_playback1_ops = {
        .prepare =     snd_sgio2audio_pcm_prepare,
        .trigger =     snd_sgio2audio_pcm_trigger,
        .pointer =     snd_sgio2audio_pcm_pointer,
-       .page =        snd_sgio2audio_page,
+       .page =        snd_pcm_lib_get_vmalloc_page,
+       .mmap =        snd_pcm_lib_mmap_vmalloc,
 };
 
 static struct snd_pcm_ops snd_sgio2audio_playback2_ops = {
@@ -721,7 +703,8 @@ static struct snd_pcm_ops snd_sgio2audio_playback2_ops = {
        .prepare =     snd_sgio2audio_pcm_prepare,
        .trigger =     snd_sgio2audio_pcm_trigger,
        .pointer =     snd_sgio2audio_pcm_pointer,
-       .page =        snd_sgio2audio_page,
+       .page =        snd_pcm_lib_get_vmalloc_page,
+       .mmap =        snd_pcm_lib_mmap_vmalloc,
 };
 
 static struct snd_pcm_ops snd_sgio2audio_capture_ops = {
@@ -733,7 +716,8 @@ static struct snd_pcm_ops snd_sgio2audio_capture_ops = {
        .prepare =     snd_sgio2audio_pcm_prepare,
        .trigger =     snd_sgio2audio_pcm_trigger,
        .pointer =     snd_sgio2audio_pcm_pointer,
-       .page =        snd_sgio2audio_page,
+       .page =        snd_pcm_lib_get_vmalloc_page,
+       .mmap =        snd_pcm_lib_mmap_vmalloc,
 };
 
 /*
index 89466b056be79c8f1515db39d517b3dede0d25c2..24d152ccf80d21ac6b751a85839bcaa8bedaa651 100644 (file)
@@ -198,7 +198,7 @@ MODULE_LICENSE("GPL");
  *     5530 only. The 5510/5520 decode is different.
  */
 
-static struct pci_device_id id_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(id_tbl) = {
        { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO), 0 },
        { }
 };
index c62530943888aaf26a18d3f11dd8afd6a80ff019..fde7c12fe5da9eac43384068c7c761b14cee193c 100644 (file)
@@ -328,11 +328,11 @@ static int sound_mixer_ioctl(int mixdev, unsigned int cmd, void __user *arg)
        return mixer_devs[mixdev]->ioctl(mixdev, cmd, arg);
 }
 
-static int sound_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, unsigned long arg)
+static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        int len = 0, dtype;
-       int dev = iminor(inode);
+       int dev = iminor(file->f_dentry->d_inode);
+       long ret = -EINVAL;
        void __user *p = (void __user *)arg;
 
        if (_SIOC_DIR(cmd) != _SIOC_NONE && _SIOC_DIR(cmd) != 0) {
@@ -353,6 +353,7 @@ static int sound_ioctl(struct inode *inode, struct file *file,
        if (cmd == OSS_GETVERSION)
                return __put_user(SOUND_VERSION, (int __user *)p);
        
+       lock_kernel();
        if (_IOC_TYPE(cmd) == 'M' && num_mixers > 0 &&   /* Mixer ioctl */
            (dev & 0x0f) != SND_DEV_CTL) {              
                dtype = dev & 0x0f;
@@ -360,24 +361,31 @@ static int sound_ioctl(struct inode *inode, struct file *file,
                case SND_DEV_DSP:
                case SND_DEV_DSP16:
                case SND_DEV_AUDIO:
-                       return sound_mixer_ioctl(audio_devs[dev >> 4]->mixer_dev,
+                       ret = sound_mixer_ioctl(audio_devs[dev >> 4]->mixer_dev,
                                                 cmd, p);
-                       
+                       break;                  
                default:
-                       return sound_mixer_ioctl(dev >> 4, cmd, p);
+                       ret = sound_mixer_ioctl(dev >> 4, cmd, p);
+                       break;
                }
+               unlock_kernel();
+               return ret;
        }
+
        switch (dev & 0x0f) {
        case SND_DEV_CTL:
                if (cmd == SOUND_MIXER_GETLEVELS)
-                       return get_mixer_levels(p);
-               if (cmd == SOUND_MIXER_SETLEVELS)
-                       return set_mixer_levels(p);
-               return sound_mixer_ioctl(dev >> 4, cmd, p);
+                       ret = get_mixer_levels(p);
+               else if (cmd == SOUND_MIXER_SETLEVELS)
+                       ret = set_mixer_levels(p);
+               else
+                       ret = sound_mixer_ioctl(dev >> 4, cmd, p);
+               break;
 
        case SND_DEV_SEQ:
        case SND_DEV_SEQ2:
-               return sequencer_ioctl(dev, file, cmd, p);
+               ret = sequencer_ioctl(dev, file, cmd, p);
+               break;
 
        case SND_DEV_DSP:
        case SND_DEV_DSP16:
@@ -390,7 +398,8 @@ static int sound_ioctl(struct inode *inode, struct file *file,
                break;
 
        }
-       return -EINVAL;
+       unlock_kernel();
+       return ret;
 }
 
 static unsigned int sound_poll(struct file *file, poll_table * wait)
@@ -490,7 +499,7 @@ const struct file_operations oss_sound_fops = {
        .read           = sound_read,
        .write          = sound_write,
        .poll           = sound_poll,
-       .ioctl          = sound_ioctl,
+       .unlocked_ioctl = sound_ioctl,
        .mmap           = sound_mmap,
        .open           = sound_open,
        .release        = sound_release,
index 351654cf7b098e72db04403cb92972bfa0bed8e2..1298c68d6bf0f880042c54f0fe29fd777fc628d2 100644 (file)
@@ -789,6 +789,7 @@ config SND_VIRTUOSO
          Say Y here to include support for sound cards based on the
          Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X,
          Essence ST (Deluxe), and Essence STX.
+         Support for the DS is experimental.
          Support for the HDAV1.3 (Deluxe) is very experimental.
 
          To compile this driver as a module, choose M here: the module
index d9266bae284977fb4bccbff7bc062d421d65cee0..1caf5e3c1f6ad481064ea70cced23293333de96a 100644 (file)
@@ -544,25 +544,10 @@ static int patch_wolfson04(struct snd_ac97 * ac97)
        return 0;
 }
 
-static int patch_wolfson_wm9705_specific(struct snd_ac97 * ac97)
-{
-       int err, i;
-       for (i = 0; i < ARRAY_SIZE(wm97xx_snd_ac97_controls); i++) {
-               if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm97xx_snd_ac97_controls[i], ac97))) < 0)
-                       return err;
-       }
-       snd_ac97_write_cache(ac97,  0x72, 0x0808);
-       return 0;
-}
-
-static struct snd_ac97_build_ops patch_wolfson_wm9705_ops = {
-       .build_specific = patch_wolfson_wm9705_specific,
-};
-
 static int patch_wolfson05(struct snd_ac97 * ac97)
 {
        /* WM9705, WM9710 */
-       ac97->build_ops = &patch_wolfson_wm9705_ops;
+       ac97->build_ops = &patch_wolfson_wm9703_ops;
 #ifdef CONFIG_TOUCHSCREEN_WM9705
        /* WM9705 touchscreen uses AUX and VIDEO for touch */
        ac97->flags |= AC97_HAS_NO_VIDEO | AC97_HAS_NO_AUX;
index 8f5098f92c370f81c937f8159827736b34c9742d..4382d0fa6b9a374c05f3eb674ed82e7d4f9cf7e0 100644 (file)
@@ -1048,7 +1048,7 @@ snd_ad1889_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_device_id snd_ad1889_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_ad1889_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_ANALOG_DEVICES, PCI_DEVICE_ID_AD1889JS) },
        { 0, },
 };
index aaf4da68969c4572c9201e06f8ddc47cbd711f60..5c6e322a48f0dfd0d3f23e78c4148be40455240a 100644 (file)
@@ -275,7 +275,7 @@ struct snd_ali {
 #endif
 };
 
-static struct pci_device_id snd_ali_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_ali_ids) = {
        {PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5451), 0, 0, 0},
        {0, }
 };
index 3aa35af7ca9170746d4a5e972a7ff01261bddc71..d7653cb7ac60dc24f5d3e07ff1537f18a32e1299 100644 (file)
@@ -145,7 +145,7 @@ struct snd_als300_substream_data {
        int block_counter_register;
 };
 
-static struct pci_device_id snd_als300_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_als300_ids) = {
        { 0x4005, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALS300 },
        { 0x4005, 0x0308, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALS300_PLUS },
        { 0, }
index 3dbacde1a5afd45475ec79cdccf7f95a3d085f2a..d75cf7b0642684a8d2f7a6ebde3ee1296ece0ea4 100644 (file)
@@ -117,7 +117,7 @@ struct snd_card_als4000 {
 #endif
 };
 
-static struct pci_device_id snd_als4000_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_als4000_ids) = {
        { 0x4005, 0x4000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* ALS4000 */
        { 0, }
 };
index 42b4fbbd8e2b196b47c967d4057a634fe004b602..49d572a7b235cd21dfc8a3f5d8069b728a9ec2dc 100644 (file)
@@ -286,7 +286,7 @@ struct atiixp {
 
 /*
  */
-static struct pci_device_id snd_atiixp_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_atiixp_ids) = {
        { PCI_VDEVICE(ATI, 0x4341), 0 }, /* SB200 */
        { PCI_VDEVICE(ATI, 0x4361), 0 }, /* SB300 */
        { PCI_VDEVICE(ATI, 0x4370), 0 }, /* SB400 */
index e7e147bf8eb2686cc98a629905f9589a0fb5357d..91d7036b64118572a7c4ffa3ed20724e1ede6c00 100644 (file)
@@ -261,7 +261,7 @@ struct atiixp_modem {
 
 /*
  */
-static struct pci_device_id snd_atiixp_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_atiixp_ids) = {
        { PCI_VDEVICE(ATI, 0x434d), 0 }, /* SB200 */
        { PCI_VDEVICE(ATI, 0x4378), 0 }, /* SB400 */
        { 0, }
index c0e8c6b295cb98df3fb8ef164f373cb35f81ba58..aa51cc7771dd9f270307cd64dc013fd6d3adbcbd 100644 (file)
@@ -1,6 +1,6 @@
 #include "au8810.h"
 #include "au88x0.h"
-static struct pci_device_id snd_vortex_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_vortex_ids) = {
        {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_ADVANTAGE), 1,},
        {0,}
 };
index a6527330df584964b5b96b82632f747e22da89f2..2f321e7306cd2c94739740dcb910c4c909d547ad 100644 (file)
@@ -1,6 +1,6 @@
 #include "au8820.h"
 #include "au88x0.h"
-static struct pci_device_id snd_vortex_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_vortex_ids) = {
        {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_1), 0,},
        {0,}
 };
index 6c702ad4352ad8198af4a062c75c9d93571f10fd..279b78f06d220f2a850671b2d29eeb3876a2c3de 100644 (file)
@@ -1,6 +1,6 @@
 #include "au8830.h"
 #include "au88x0.h"
-static struct pci_device_id snd_vortex_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_vortex_ids) = {
        {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_2), 0,},
        {0,}
 };
index 4d34bb0d99d327120dde4bf5bea211f98a30105a..67921f93a41e08eefc0a2899537d6a5fe071a4e7 100644 (file)
@@ -164,7 +164,7 @@ MODULE_PARM_DESC(id, "ID string for the Audiowerk2 soundcard.");
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable Audiowerk2 soundcard.");
 
-static struct pci_device_id snd_aw2_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_aw2_ids) = {
        {PCI_VENDOR_ID_SAA7146, PCI_DEVICE_ID_SAA7146, 0, 0,
         0, 0, 0},
        {0}
index 69867ace7860be8774f9081432abbb7b74e9c2cb..4679ed83a43b8687402b7efca98ed47a0518ac98 100644 (file)
@@ -350,7 +350,7 @@ struct snd_azf3328 {
 #endif
 };
 
-static const struct pci_device_id snd_azf3328_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_azf3328_ids) = {
        { 0x122D, 0x50DC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },   /* PCI168/3328 */
        { 0x122D, 0x80DA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },   /* 3328 */
        { 0, }
index 4e2b925a94cc0af1cb586609d65aaed7ca36ed5b..37e1b5df5ab8d7b7bbfad9c7dd6afcfd56c537e2 100644 (file)
@@ -795,7 +795,7 @@ fail:
          .driver_data = SND_BT87X_BOARD_ ## id }
 /* driver_data is the card id for that device */
 
-static struct pci_device_id snd_bt87x_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_bt87x_ids) = {
        /* Hauppauge WinTV series */
        BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0x13eb, GENERIC),
        /* Hauppauge WinTV series */
@@ -964,7 +964,7 @@ static void __devexit snd_bt87x_remove(struct pci_dev *pci)
 
 /* default entries for all Bt87x cards - it's not exported */
 /* driver_data is set to 0 to call detection */
-static struct pci_device_id snd_bt87x_default_ids[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(snd_bt87x_default_ids) = {
        BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, PCI_ANY_ID, PCI_ANY_ID, UNKNOWN),
        BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, PCI_ANY_ID, PCI_ANY_ID, UNKNOWN),
        { }
index 15e4138bce17ea4b42b2904bbe29b43095252d38..0a3d3d6e77b4d668bad27a929cda8fa174d1cd1c 100644 (file)
@@ -1875,7 +1875,7 @@ static int snd_ca0106_resume(struct pci_dev *pci)
 #endif
 
 // PCI IDs
-static struct pci_device_id snd_ca0106_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_ca0106_ids) = {
        { PCI_VDEVICE(CREATIVE, 0x0007), 0 },   /* Audigy LS or Live 24bit */
        { 0, }
 };
index a312bae08f52d5552b07e6ff05b446a7f768d98d..1ded64e056433e22f8e96d8b0fbeb6dbf2c557d4 100644 (file)
@@ -2796,7 +2796,7 @@ static inline void snd_cmipci_proc_init(struct cmipci *cm) {}
 #endif
 
 
-static struct pci_device_id snd_cmipci_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_cmipci_ids) = {
        {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A), 0},
        {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B), 0},
        {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738), 0},
@@ -3018,7 +3018,7 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc
        int integrated_midi = 0;
        char modelstr[16];
        int pcm_index, pcm_spdif_index;
-       static struct pci_device_id intel_82437vx[] = {
+       static DEFINE_PCI_DEVICE_TABLE(intel_82437vx) = {
                { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437VX) },
                { },
        };
index e2e0359bb0568ca98999f2512baeb83e67a55883..9edc65059e3e4e02fe76ed6526613591c213b089 100644 (file)
@@ -494,7 +494,7 @@ struct cs4281 {
 
 static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id);
 
-static struct pci_device_id snd_cs4281_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_cs4281_ids) = {
        { PCI_VDEVICE(CIRRUS, 0x6005), 0, },    /* CS4281 */
        { 0, }
 };
index 033aec430117ac698c50cfe7514e26b6b792bdbd..767fa7f06cd0857e3ca2cf22ec333fbc683e0215 100644 (file)
@@ -64,7 +64,7 @@ MODULE_PARM_DESC(thinkpad, "Force to enable Thinkpad's CLKRUN control.");
 module_param_array(mmap_valid, bool, NULL, 0444);
 MODULE_PARM_DESC(mmap_valid, "Support OSS mmap.");
 
-static struct pci_device_id snd_cs46xx_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_cs46xx_ids) = {
        { PCI_VDEVICE(CIRRUS, 0x6001), 0, },   /* CS4280 */
        { PCI_VDEVICE(CIRRUS, 0x6003), 0, },   /* CS4612 */
        { PCI_VDEVICE(CIRRUS, 0x6004), 0, },   /* CS4615 */
index 1be96ead42448d08be408f3f05993a9d76a14a82..3f99a5e8528cf953207407c4ff3f51a5b1f028ee 100644 (file)
@@ -2238,11 +2238,11 @@ static void snd_cs46xx_codec_reset (struct snd_ac97 * ac97)
 
        /* set the desired CODEC mode */
        if (ac97->num == CS46XX_PRIMARY_CODEC_INDEX) {
-               snd_printdd("cs46xx: CODOEC1 mode %04x\n",0x0);
-               snd_cs46xx_ac97_write(ac97,AC97_CSR_ACMODE,0x0);
+               snd_printdd("cs46xx: CODEC1 mode %04x\n", 0x0);
+               snd_cs46xx_ac97_write(ac97, AC97_CSR_ACMODE, 0x0);
        } else if (ac97->num == CS46XX_SECONDARY_CODEC_INDEX) {
-               snd_printdd("cs46xx: CODOEC2 mode %04x\n",0x3);
-               snd_cs46xx_ac97_write(ac97,AC97_CSR_ACMODE,0x3);
+               snd_printdd("cs46xx: CODEC2 mode %04x\n", 0x3);
+               snd_cs46xx_ac97_write(ac97, AC97_CSR_ACMODE, 0x3);
        } else {
                snd_BUG(); /* should never happen ... */
        }
@@ -2266,7 +2266,7 @@ static void snd_cs46xx_codec_reset (struct snd_ac97 * ac97)
                        return;
 
                /* test if we can write to the record gain volume register */
-               snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x8a05);
+               snd_ac97_write(ac97, AC97_REC_GAIN, 0x8a05);
                if ((err = snd_ac97_read(ac97, AC97_REC_GAIN)) == 0x8a05)
                        return;
 
@@ -3597,7 +3597,7 @@ static struct cs_card_type __devinitdata cards[] = {
 #ifdef CONFIG_PM
 static unsigned int saved_regs[] = {
        BA0_ACOSV,
-       BA0_ASER_FADDR,
+       /*BA0_ASER_FADDR,*/
        BA0_ASER_MASTER,
        BA1_PVOL,
        BA1_CVOL,
@@ -3644,6 +3644,7 @@ int snd_cs46xx_resume(struct pci_dev *pci)
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
        int i;
 #endif
+       unsigned int tmp;
 
        pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
@@ -3685,6 +3686,15 @@ int snd_cs46xx_resume(struct pci_dev *pci)
        snd_ac97_resume(chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]);
        snd_ac97_resume(chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]);
 
+       /*
+         *  Stop capture DMA.
+        */
+       tmp = snd_cs46xx_peek(chip, BA1_CCTL);
+       chip->capt.ctl = tmp & 0x0000ffff;
+       snd_cs46xx_poke(chip, BA1_CCTL, tmp & 0xffff0000);
+
+       mdelay(5);
+
        /* reset playback/capture */
        snd_cs46xx_set_play_sample_rate(chip, 8000);
        snd_cs46xx_set_capture_sample_rate(chip, 8000);
index f4f0c8f5dad76ab71cf57eaf835bfda69922c972..3e5ca8fb519ff1ae5d2c03cf7f2beb8700b1745d 100644 (file)
@@ -298,6 +298,9 @@ void  cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip)
                if (ins->scbs[i].deleted) continue;
 
                cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) );
+#ifdef CONFIG_PM
+               kfree(ins->scbs[i].data);
+#endif
        }
 
        kfree(ins->code.data);
@@ -974,13 +977,11 @@ static struct dsp_scb_descriptor * _map_scb (struct snd_cs46xx *chip, char * nam
 
        index = find_free_scb_index (ins);
 
+       memset(&ins->scbs[index], 0, sizeof(ins->scbs[index]));
        strcpy(ins->scbs[index].scb_name, name);
        ins->scbs[index].address = dest;
        ins->scbs[index].index = index;
-       ins->scbs[index].proc_info = NULL;
        ins->scbs[index].ref_count = 1;
-       ins->scbs[index].deleted = 0;
-       spin_lock_init(&ins->scbs[index].lock);
 
        desc = (ins->scbs + index);
        ins->scbs[index].scb_symbol = add_symbol (chip, name, dest, SYMBOL_PARAMETER);
@@ -1022,17 +1023,29 @@ _map_task_tree (struct snd_cs46xx *chip, char * name, u32 dest, u32 size)
        return desc;
 }
 
+#define SCB_BYTES      (0x10 * 4)
+
 struct dsp_scb_descriptor *
 cs46xx_dsp_create_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32 dest)
 {
        struct dsp_scb_descriptor * desc;
 
+#ifdef CONFIG_PM
+       /* copy the data for resume */
+       scb_data = kmemdup(scb_data, SCB_BYTES, GFP_KERNEL);
+       if (!scb_data)
+               return NULL;
+#endif
+
        desc = _map_scb (chip,name,dest);
        if (desc) {
                desc->data = scb_data;
                _dsp_create_scb(chip,scb_data,dest);
        } else {
                snd_printk(KERN_ERR "dsp_spos: failed to map SCB\n");
+#ifdef CONFIG_PM
+               kfree(scb_data);
+#endif
        }
 
        return desc;
@@ -1988,7 +2001,28 @@ int cs46xx_dsp_resume(struct snd_cs46xx * chip)
                        continue;
                _dsp_create_scb(chip, s->data, s->address);
        }
-
+       for (i = 0; i < ins->nscb; i++) {
+               struct dsp_scb_descriptor *s = &ins->scbs[i];
+               if (s->deleted)
+                       continue;
+               if (s->updated)
+                       cs46xx_dsp_spos_update_scb(chip, s);
+               if (s->volume_set)
+                       cs46xx_dsp_scb_set_volume(chip, s,
+                                                 s->volume[0], s->volume[1]);
+       }
+       if (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) {
+               cs46xx_dsp_enable_spdif_hw(chip);
+               snd_cs46xx_poke(chip, (ins->ref_snoop_scb->address + 2) << 2,
+                               (OUTPUT_SNOOP_BUFFER + 0x10) << 0x10);
+               if (ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN)
+                       cs46xx_poke_via_dsp(chip, SP_SPDOUT_CSUV,
+                                           ins->spdif_csuv_stream);
+       }
+       if (chip->dsp_spos_instance->spdif_status_in) {
+               cs46xx_poke_via_dsp(chip, SP_ASER_COUNTDOWN, 0x80000005);
+               cs46xx_poke_via_dsp(chip, SP_SPDIN_CONTROL, 0x800003ff);
+       }
        return 0;
 }
 #endif
index f9e169d33c03032d21c777805c8fe05880f5583f..ca47a8114c7f9e9ed366772f6d5fc8780bc674c1 100644 (file)
@@ -212,6 +212,7 @@ static inline void cs46xx_dsp_spos_update_scb (struct snd_cs46xx * chip,
                        (scb->address + SCBsubListPtr) << 2,
                        (scb->sub_list_ptr->address << 0x10) |
                        (scb->next_scb_ptr->address));  
+       scb->updated = 1;
 }
 
 static inline void cs46xx_dsp_scb_set_volume (struct snd_cs46xx * chip,
@@ -222,6 +223,9 @@ static inline void cs46xx_dsp_scb_set_volume (struct snd_cs46xx * chip,
 
        snd_cs46xx_poke(chip, (scb->address + SCBVolumeCtrl) << 2, val);
        snd_cs46xx_poke(chip, (scb->address + SCBVolumeCtrl + 1) << 2, val);
+       scb->volume_set = 1;
+       scb->volume[0] = left;
+       scb->volume[1] = right;
 }
 #endif /* __DSP_SPOS_H__ */
 #endif /* CONFIG_SND_CS46XX_NEW_DSP  */
index dd7c41b037b45e0700c55db9e32851a04e34ef55..00b148a10239f4d0f97caba451fd6d0b3b4d46c0 100644 (file)
@@ -115,7 +115,6 @@ static void cs46xx_dsp_proc_scb_info_read (struct snd_info_entry *entry,
 static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
 {
        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
-       unsigned long flags;
 
        if ( scb->parent_scb_ptr ) {
                /* unlink parent SCB */
@@ -153,8 +152,6 @@ static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor
                        scb->next_scb_ptr = ins->the_null_scb;
                }
 
-               spin_lock_irqsave(&chip->reg_lock, flags);    
-
                /* update parent first entry in DSP RAM */
                cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
 
@@ -162,7 +159,6 @@ static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor
                cs46xx_dsp_spos_update_scb(chip,scb);
 
                scb->parent_scb_ptr = NULL;
-               spin_unlock_irqrestore(&chip->reg_lock, flags);
        }
 }
 
@@ -197,9 +193,9 @@ void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor *
                goto _end;
 #endif
 
-       spin_lock_irqsave(&scb->lock, flags);
+       spin_lock_irqsave(&chip->reg_lock, flags);    
        _dsp_unlink_scb (chip,scb);
-       spin_unlock_irqrestore(&scb->lock, flags);
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
 
        cs46xx_dsp_proc_free_scb_desc(scb);
        if (snd_BUG_ON(!scb->scb_symbol))
@@ -207,6 +203,10 @@ void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor *
        remove_symbol (chip,scb->scb_symbol);
 
        ins->scbs[scb->index].deleted = 1;
+#ifdef CONFIG_PM
+       kfree(ins->scbs[scb->index].data);
+       ins->scbs[scb->index].data = NULL;
+#endif
 
        if (scb->index < ins->scb_highest_frag_index)
                ins->scb_highest_frag_index = scb->index;
@@ -1508,20 +1508,17 @@ int cs46xx_dsp_pcm_unlink (struct snd_cs46xx * chip,
                       chip->dsp_spos_instance->npcm_channels <= 0))
                return -EIO;
 
-       spin_lock(&pcm_channel->src_scb->lock);
-
+       spin_lock_irqsave(&chip->reg_lock, flags);
        if (pcm_channel->unlinked) {
-               spin_unlock(&pcm_channel->src_scb->lock);
+               spin_unlock_irqrestore(&chip->reg_lock, flags);
                return -EIO;
        }
 
-       spin_lock_irqsave(&chip->reg_lock, flags);
        pcm_channel->unlinked = 1;
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
 
        _dsp_unlink_scb (chip,pcm_channel->pcm_reader_scb);
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
 
-       spin_unlock(&pcm_channel->src_scb->lock);
        return 0;
 }
 
@@ -1533,10 +1530,10 @@ int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip,
        struct dsp_scb_descriptor * src_scb = pcm_channel->src_scb;
        unsigned long flags;
 
-       spin_lock(&pcm_channel->src_scb->lock);
+       spin_lock_irqsave(&chip->reg_lock, flags);
 
        if (pcm_channel->unlinked == 0) {
-               spin_unlock(&pcm_channel->src_scb->lock);
+               spin_unlock_irqrestore(&chip->reg_lock, flags);
                return -EIO;
        }
 
@@ -1552,8 +1549,6 @@ int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip,
        snd_BUG_ON(pcm_channel->pcm_reader_scb->parent_scb_ptr);
        pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb;
 
-       spin_lock_irqsave(&chip->reg_lock, flags);
-
        /* update SCB entry in DSP RAM */
        cs46xx_dsp_spos_update_scb(chip,pcm_channel->pcm_reader_scb);
 
@@ -1562,8 +1557,6 @@ int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip,
 
        pcm_channel->unlinked = 0;
        spin_unlock_irqrestore(&chip->reg_lock, flags);
-
-       spin_unlock(&pcm_channel->src_scb->lock);
        return 0;
 }
 
@@ -1596,13 +1589,17 @@ cs46xx_add_record_source (struct snd_cs46xx *chip, struct dsp_scb_descriptor * s
 
 int cs46xx_src_unlink(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
 {
+       unsigned long flags;
+
        if (snd_BUG_ON(!src->parent_scb_ptr))
                return -EINVAL;
 
        /* mute SCB */
        cs46xx_dsp_scb_set_volume (chip,src,0,0);
 
+       spin_lock_irqsave(&chip->reg_lock, flags);
        _dsp_unlink_scb (chip,src);
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
 
        return 0;
 }
index dc464321d0f3ebda294e8e45de1db429122f4bc7..207479a641cff3fb115ff75f0cd861ec56227fe4 100644 (file)
@@ -58,7 +58,7 @@ struct snd_cs5530 {
        unsigned long pci_base;
 };
 
-static struct pci_device_id snd_cs5530_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_cs5530_ids) = {
        {PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO, PCI_ANY_ID,
                                                        PCI_ANY_ID, 0, 0},
        {0,}
index 91e7faf69bbb3732dc7eb224635c6728fec31396..afb803708416e4dec1b0e7182f288b34243797f4 100644 (file)
@@ -66,7 +66,7 @@ MODULE_PARM_DESC(id, "ID string for " DRIVER_NAME);
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable " DRIVER_NAME);
 
-static struct pci_device_id snd_cs5535audio_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_cs5535audio_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_AUDIO) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_AUDIO) },
        {}
index 459c1f62783b627c2988c7d95ce5935c31e698f4..480cb1e905b61af9a5c3c12aaed35da17376ecd5 100644 (file)
@@ -1214,10 +1214,11 @@ static int atc_dev_free(struct snd_device *dev)
        return ct_atc_destroy(atc);
 }
 
-static int __devinit atc_identify_card(struct ct_atc *atc)
+static int __devinit atc_identify_card(struct ct_atc *atc, unsigned int ssid)
 {
        const struct snd_pci_quirk *p;
        const struct snd_pci_quirk *list;
+       u16 vendor_id, device_id;
 
        switch (atc->chip_type) {
        case ATC20K1:
@@ -1231,13 +1232,19 @@ static int __devinit atc_identify_card(struct ct_atc *atc)
        default:
                return -ENOENT;
        }
-       p = snd_pci_quirk_lookup(atc->pci, list);
+       if (ssid) {
+               vendor_id = ssid >> 16;
+               device_id = ssid & 0xffff;
+       } else {
+               vendor_id = atc->pci->subsystem_vendor;
+               device_id = atc->pci->subsystem_device;
+       }
+       p = snd_pci_quirk_lookup_id(vendor_id, device_id, list);
        if (p) {
                if (p->value < 0) {
                        printk(KERN_ERR "ctxfi: "
                               "Device %04x:%04x is black-listed\n",
-                              atc->pci->subsystem_vendor,
-                              atc->pci->subsystem_device);
+                              vendor_id, device_id);
                        return -ENOENT;
                }
                atc->model = p->value;
@@ -1250,8 +1257,7 @@ static int __devinit atc_identify_card(struct ct_atc *atc)
        atc->model_name = ct_subsys_name[atc->model];
        snd_printd("ctxfi: chip %s model %s (%04x:%04x) is found\n",
                   atc->chip_name, atc->model_name,
-                  atc->pci->subsystem_vendor,
-                  atc->pci->subsystem_device);
+                  vendor_id, device_id);
        return 0;
 }
 
@@ -1625,7 +1631,8 @@ static struct ct_atc atc_preset __devinitdata = {
 
 int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci,
                            unsigned int rsr, unsigned int msr,
-                           int chip_type, struct ct_atc **ratc)
+                           int chip_type, unsigned int ssid,
+                           struct ct_atc **ratc)
 {
        struct ct_atc *atc;
        static struct snd_device_ops ops = {
@@ -1651,7 +1658,7 @@ int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci,
        mutex_init(&atc->atc_mutex);
 
        /* Find card model */
-       err = atc_identify_card(atc);
+       err = atc_identify_card(atc, ssid);
        if (err < 0) {
                printk(KERN_ERR "ctatc: Card not recognised\n");
                goto error1;
index 9fd8a57089434d3c16b178664a8980aaa88836c7..7167c0185d5281cb2c2a77bc978ce4c3dbdbdb5f 100644 (file)
@@ -148,7 +148,7 @@ struct ct_atc {
 
 int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci,
                            unsigned int rsr, unsigned int msr, int chip_type,
-                           struct ct_atc **ratc);
+                           unsigned int subsysid, struct ct_atc **ratc);
 int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc);
 
 #endif /* CTATC_H */
index 76541748e7bcf8ec43ccd5964d90faf4258f442a..f42e7e1a107457bf99091d5813b438a88fe31f2f 100644 (file)
@@ -32,6 +32,7 @@ module_param(multiple, uint, S_IRUGO);
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+static unsigned int subsystem[SNDRV_CARDS];
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for Creative X-Fi driver");
@@ -39,8 +40,10 @@ module_param_array(id, charp, NULL, 0444);
 MODULE_PARM_DESC(id, "ID string for Creative X-Fi driver");
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable Creative X-Fi driver");
+module_param_array(subsystem, int, NULL, 0444);
+MODULE_PARM_DESC(subsystem, "Override subsystem ID for Creative X-Fi driver");
 
-static struct pci_device_id ct_pci_dev_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(ct_pci_dev_ids) = {
        /* only X-Fi is supported, so... */
        { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_20K1),
          .driver_data = ATC20K1,
@@ -85,7 +88,7 @@ ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
                multiple = 2;
        }
        err = ct_atc_create(card, pci, reference_rate, multiple,
-                           pci_id->driver_data, &atc);
+                           pci_id->driver_data, subsystem[dev], &atc);
        if (err < 0)
                goto error;
 
index 8c6db3aa3c1ad59d55ae51d67fbb5b112140c0f2..a65bafe0800f8c727569024e699f395231d4a46a 100644 (file)
@@ -63,7 +63,7 @@ static const struct firmware card_fw[] = {
        {0, "darla20_dsp.fw"}
 };
 
-static struct pci_device_id snd_echo_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = {
        {0x1057, 0x1801, 0xECC0, 0x0010, 0, 0, 0},      /* DSP 56301 Darla20 rev.0 */
        {0,}
 };
index 29043301ebb867aaaf32f0b6221905407e0f5a0f..20c7cbc89bb38aff3042e5b5a603de7af286a7f5 100644 (file)
@@ -45,7 +45,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        chip->device_id = device_id;
        chip->subdevice_id = subdevice_id;
        chip->bad_board = TRUE;
-       chip->dsp_code_to_load = &card_fw[FW_DARLA20_DSP];
+       chip->dsp_code_to_load = FW_DARLA20_DSP;
        chip->spdif_status = GD_SPDIF_STATUS_UNDEF;
        chip->clock_state = GD_CLOCK_UNDEF;
        /* Since this card has no ASIC, mark it as loaded so everything
@@ -57,15 +57,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
                return err;
        chip->bad_board = FALSE;
 
-       if ((err = init_line_levels(chip)) < 0)
-               return err;
-
        DE_INIT(("init_hw done\n"));
        return err;
 }
 
 
 
+static int set_mixer_defaults(struct echoaudio *chip)
+{
+       return init_line_levels(chip);
+}
+
+
+
 /* The Darla20 has no external clock sources */
 static u32 detect_input_clocks(const struct echoaudio *chip)
 {
index 04cbf3eaf05a1cd8ae683d1ca2d39be50b0f5156..0a6c50bcd758073c0a7ba0de4043c886c71a2351 100644 (file)
@@ -67,7 +67,7 @@ static const struct firmware card_fw[] = {
        {0, "darla24_dsp.fw"}
 };
 
-static struct pci_device_id snd_echo_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = {
        {0x1057, 0x1801, 0xECC0, 0x0040, 0, 0, 0},      /* DSP 56301 Darla24 rev.0 */
        {0x1057, 0x1801, 0xECC0, 0x0041, 0, 0, 0},      /* DSP 56301 Darla24 rev.1 */
        {0,}
index 60228731841f84fc2b1bc814242f9e9d06839451..6da6663e9176eb467c794b5772acaf0b3fb271ab 100644 (file)
@@ -45,7 +45,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        chip->device_id = device_id;
        chip->subdevice_id = subdevice_id;
        chip->bad_board = TRUE;
-       chip->dsp_code_to_load = &card_fw[FW_DARLA24_DSP];
+       chip->dsp_code_to_load = FW_DARLA24_DSP;
        /* Since this card has no ASIC, mark it as loaded so everything
           works OK */
        chip->asic_loaded = TRUE;
@@ -56,15 +56,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
                return err;
        chip->bad_board = FALSE;
 
-       if ((err = init_line_levels(chip)) < 0)
-               return err;
-
        DE_INIT(("init_hw done\n"));
        return err;
 }
 
 
 
+static int set_mixer_defaults(struct echoaudio *chip)
+{
+       return init_line_levels(chip);
+}
+
+
+
 static u32 detect_input_clocks(const struct echoaudio *chip)
 {
        u32 clocks_from_dsp, clock_bits;
index 4022e43a0053dc36fa04ed958d74f7c86f790e98..f5142796989b074480949b61a39c73c55f4ce7a3 100644 (file)
@@ -81,7 +81,7 @@ static const struct firmware card_fw[] = {
        {0, "3g_asic.fw"}
 };
 
-static struct pci_device_id snd_echo_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = {
        {0x1057, 0x3410, 0xECC0, 0x0100, 0, 0, 0},      /* Echo 3G */
        {0,}
 };
index 57967e580571ffaf6634d5a8d5e265c4c9101d83..3cdc2ee2d1dd900d97c431a3180a405230f70b5a 100644 (file)
@@ -61,7 +61,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        chip->subdevice_id = subdevice_id;
        chip->bad_board = TRUE;
        chip->has_midi = TRUE;
-       chip->dsp_code_to_load = &card_fw[FW_ECHO3G_DSP];
+       chip->dsp_code_to_load = FW_ECHO3G_DSP;
 
        /* Load the DSP code and the ASIC on the PCI card and get
        what type of external box is attached */
@@ -97,20 +97,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        chip->digital_modes =   ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA |
                                ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL |
                                ECHOCAPS_HAS_DIGITAL_MODE_ADAT;
-       chip->digital_mode =    DIGITAL_MODE_SPDIF_RCA;
-       chip->professional_spdif = FALSE;
-       chip->non_audio_spdif = FALSE;
-       chip->bad_board = FALSE;
-
-       if ((err = init_line_levels(chip)) < 0)
-               return err;
-       err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA);
-       if (err < 0)
-               return err;
-       err = set_phantom_power(chip, 0);
-       if (err < 0)
-               return err;
-       err = set_professional_spdif(chip, TRUE);
 
        DE_INIT(("init_hw done\n"));
        return err;
@@ -118,6 +104,18 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
 
 
 
+static int set_mixer_defaults(struct echoaudio *chip)
+{
+       chip->digital_mode = DIGITAL_MODE_SPDIF_RCA;
+       chip->professional_spdif = FALSE;
+       chip->non_audio_spdif = FALSE;
+       chip->bad_board = FALSE;
+       chip->phantom_power = FALSE;
+       return init_line_levels(chip);
+}
+
+
+
 static int set_phantom_power(struct echoaudio *chip, char on)
 {
        u32 control_reg = le32_to_cpu(chip->comm_page->control_register);
index 1305f7ca02c3c2726049dc448dec6b7fa36a63cd..8dab82d7d19d1368abdcb26dd25b7ae581a058b2 100644 (file)
@@ -36,22 +36,61 @@ MODULE_PARM_DESC(enable, "Enable " ECHOCARD_NAME " soundcard.");
 static unsigned int channels_list[10] = {1, 2, 4, 6, 8, 10, 12, 14, 16, 999999};
 static const DECLARE_TLV_DB_SCALE(db_scale_output_gain, -12800, 100, 1);
 
+
+
 static int get_firmware(const struct firmware **fw_entry,
-                       const struct firmware *frm, struct echoaudio *chip)
+                       struct echoaudio *chip, const short fw_index)
 {
        int err;
        char name[30];
-       DE_ACT(("firmware requested: %s\n", frm->data));
-       snprintf(name, sizeof(name), "ea/%s", frm->data);
-       if ((err = request_firmware(fw_entry, name, pci_device(chip))) < 0)
+
+#ifdef CONFIG_PM
+       if (chip->fw_cache[fw_index]) {
+               DE_ACT(("firmware requested: %s is cached\n", card_fw[fw_index].data));
+               *fw_entry = chip->fw_cache[fw_index];
+               return 0;
+       }
+#endif
+
+       DE_ACT(("firmware requested: %s\n", card_fw[fw_index].data));
+       snprintf(name, sizeof(name), "ea/%s", card_fw[fw_index].data);
+       err = request_firmware(fw_entry, name, pci_device(chip));
+       if (err < 0)
                snd_printk(KERN_ERR "get_firmware(): Firmware not available (%d)\n", err);
+#ifdef CONFIG_PM
+       else
+               chip->fw_cache[fw_index] = *fw_entry;
+#endif
        return err;
 }
 
+
+
 static void free_firmware(const struct firmware *fw_entry)
 {
+#ifdef CONFIG_PM
+       DE_ACT(("firmware not released (kept in cache)\n"));
+#else
        release_firmware(fw_entry);
        DE_ACT(("firmware released\n"));
+#endif
+}
+
+
+
+static void free_firmware_cache(struct echoaudio *chip)
+{
+#ifdef CONFIG_PM
+       int i;
+
+       for (i = 0; i < 8 ; i++)
+               if (chip->fw_cache[i]) {
+                       release_firmware(chip->fw_cache[i]);
+                       DE_ACT(("release_firmware(%d)\n", i));
+               }
+
+       DE_ACT(("firmware_cache released\n"));
+#endif
 }
 
 
@@ -714,6 +753,8 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 
        spin_lock(&chip->lock);
        switch (cmd) {
+       case SNDRV_PCM_TRIGGER_RESUME:
+               DE_ACT(("pcm_trigger resume\n"));
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                DE_ACT(("pcm_trigger start\n"));
@@ -737,6 +778,8 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd)
                err = start_transport(chip, channelmask,
                                      chip->pipe_cyclic_mask);
                break;
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               DE_ACT(("pcm_trigger suspend\n"));
        case SNDRV_PCM_TRIGGER_STOP:
                DE_ACT(("pcm_trigger stop\n"));
                for (i = 0; i < DSP_MAXPIPES; i++) {
@@ -1821,7 +1864,9 @@ static irqreturn_t snd_echo_interrupt(int irq, void *dev_id)
        /* The hardware doesn't tell us which substream caused the irq,
        thus we have to check all running substreams. */
        for (ss = 0; ss < DSP_MAXPIPES; ss++) {
-               if ((substream = chip->substream[ss])) {
+               substream = chip->substream[ss];
+               if (substream && ((struct audiopipe *)substream->runtime->
+                               private_data)->state == PIPE_STATE_STARTED) {
                        period = pcm_pointer(substream) /
                                substream->runtime->period_size;
                        if (period != chip->last_period[ss]) {
@@ -1874,6 +1919,7 @@ static int snd_echo_free(struct echoaudio *chip)
        pci_disable_device(chip->pci);
 
        /* release chip data */
+       free_firmware_cache(chip);
        kfree(chip);
        DE_INIT(("Chip freed.\n"));
        return 0;
@@ -1911,18 +1957,27 @@ static __devinit int snd_echo_create(struct snd_card *card,
                return err;
        pci_set_master(pci);
 
-       /* allocate a chip-specific data */
-       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
-       if (!chip) {
-               pci_disable_device(pci);
-               return -ENOMEM;
+       /* Allocate chip if needed */
+       if (!*rchip) {
+               chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+               if (!chip) {
+                       pci_disable_device(pci);
+                       return -ENOMEM;
+               }
+               DE_INIT(("chip=%p\n", chip));
+               spin_lock_init(&chip->lock);
+               chip->card = card;
+               chip->pci = pci;
+               chip->irq = -1;
+               atomic_set(&chip->opencount, 0);
+               mutex_init(&chip->mode_mutex);
+               chip->can_set_rate = 1;
+       } else {
+               /* If this was called from the resume function, chip is
+                * already allocated and it contains current card settings.
+                */
+               chip = *rchip;
        }
-       DE_INIT(("chip=%p\n", chip));
-
-       spin_lock_init(&chip->lock);
-       chip->card = card;
-       chip->pci = pci;
-       chip->irq = -1;
 
        /* PCI resource allocation */
        chip->dsp_registers_phys = pci_resource_start(pci, 0);
@@ -1962,7 +2017,9 @@ static __devinit int snd_echo_create(struct snd_card *card,
        chip->comm_page = (struct comm_page *)chip->commpage_dma_buf.area;
 
        err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device);
-       if (err) {
+       if (err >= 0)
+               err = set_mixer_defaults(chip);
+       if (err < 0) {
                DE_INIT(("init_hw err=%d\n", err));
                snd_echo_free(chip);
                return err;
@@ -1973,9 +2030,6 @@ static __devinit int snd_echo_create(struct snd_card *card,
                snd_echo_free(chip);
                return err;
        }
-       atomic_set(&chip->opencount, 0);
-       mutex_init(&chip->mode_mutex);
-       chip->can_set_rate = 1;
        *rchip = chip;
        /* Init done ! */
        return 0;
@@ -2008,6 +2062,7 @@ static int __devinit snd_echo_probe(struct pci_dev *pci,
 
        snd_card_set_dev(card, &pci->dev);
 
+       chip = NULL;    /* Tells snd_echo_create to allocate chip */
        if ((err = snd_echo_create(card, pci, &chip)) < 0) {
                snd_card_free(card);
                return err;
@@ -2147,6 +2202,112 @@ ctl_error:
 
 
 
+#if defined(CONFIG_PM)
+
+static int snd_echo_suspend(struct pci_dev *pci, pm_message_t state)
+{
+       struct echoaudio *chip = pci_get_drvdata(pci);
+
+       DE_INIT(("suspend start\n"));
+       snd_pcm_suspend_all(chip->analog_pcm);
+       snd_pcm_suspend_all(chip->digital_pcm);
+
+#ifdef ECHOCARD_HAS_MIDI
+       /* This call can sleep */
+       if (chip->midi_out)
+               snd_echo_midi_output_trigger(chip->midi_out, 0);
+#endif
+       spin_lock_irq(&chip->lock);
+       if (wait_handshake(chip)) {
+               spin_unlock_irq(&chip->lock);
+               return -EIO;
+       }
+       clear_handshake(chip);
+       if (send_vector(chip, DSP_VC_GO_COMATOSE) < 0) {
+               spin_unlock_irq(&chip->lock);
+               return -EIO;
+       }
+       spin_unlock_irq(&chip->lock);
+
+       chip->dsp_code = NULL;
+       free_irq(chip->irq, chip);
+       chip->irq = -1;
+       pci_save_state(pci);
+       pci_disable_device(pci);
+
+       DE_INIT(("suspend done\n"));
+       return 0;
+}
+
+
+
+static int snd_echo_resume(struct pci_dev *pci)
+{
+       struct echoaudio *chip = pci_get_drvdata(pci);
+       struct comm_page *commpage, *commpage_bak;
+       u32 pipe_alloc_mask;
+       int err;
+
+       DE_INIT(("resume start\n"));
+       pci_restore_state(pci);
+       commpage_bak = kmalloc(sizeof(struct echoaudio), GFP_KERNEL);
+       commpage = chip->comm_page;
+       memcpy(commpage_bak, commpage, sizeof(struct comm_page));
+
+       err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device);
+       if (err < 0) {
+               kfree(commpage_bak);
+               DE_INIT(("resume init_hw err=%d\n", err));
+               snd_echo_free(chip);
+               return err;
+       }
+       DE_INIT(("resume init OK\n"));
+
+       /* Temporarily set chip->pipe_alloc_mask=0 otherwise
+        * restore_dsp_settings() fails.
+        */
+       pipe_alloc_mask = chip->pipe_alloc_mask;
+       chip->pipe_alloc_mask = 0;
+       err = restore_dsp_rettings(chip);
+       chip->pipe_alloc_mask = pipe_alloc_mask;
+       if (err < 0) {
+               kfree(commpage_bak);
+               return err;
+       }
+       DE_INIT(("resume restore OK\n"));
+
+       memcpy(&commpage->audio_format, &commpage_bak->audio_format,
+               sizeof(commpage->audio_format));
+       memcpy(&commpage->sglist_addr, &commpage_bak->sglist_addr,
+               sizeof(commpage->sglist_addr));
+       memcpy(&commpage->midi_output, &commpage_bak->midi_output,
+               sizeof(commpage->midi_output));
+       kfree(commpage_bak);
+
+       if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED,
+                       ECHOCARD_NAME, chip)) {
+               snd_echo_free(chip);
+               snd_printk(KERN_ERR "cannot grab irq\n");
+               return -EBUSY;
+       }
+       chip->irq = pci->irq;
+       DE_INIT(("resume irq=%d\n", chip->irq));
+
+#ifdef ECHOCARD_HAS_MIDI
+       if (chip->midi_input_enabled)
+               enable_midi_input(chip, TRUE);
+       if (chip->midi_out)
+               snd_echo_midi_output_trigger(chip->midi_out, 1);
+#endif
+
+       DE_INIT(("resume done\n"));
+       return 0;
+}
+
+#endif /* CONFIG_PM */
+
+
+
 static void __devexit snd_echo_remove(struct pci_dev *pci)
 {
        struct echoaudio *chip;
@@ -2169,6 +2330,10 @@ static struct pci_driver driver = {
        .id_table = snd_echo_ids,
        .probe = snd_echo_probe,
        .remove = __devexit_p(snd_echo_remove),
+#ifdef CONFIG_PM
+       .suspend = snd_echo_suspend,
+       .resume = snd_echo_resume,
+#endif /* CONFIG_PM */
 };
 
 
index f9490ae36c2e6eeefafcd3d995b06d7db0bbc529..1df974dcb5f4b9b37a7e1727645a3fcbec50d0d9 100644 (file)
@@ -442,13 +442,16 @@ struct echoaudio {
        u16 device_id, subdevice_id;
        u16 *dsp_code;                  /* Current DSP code loaded,
                                         * NULL if nothing loaded */
-       const struct firmware *dsp_code_to_load;/* DSP code to load */
-       const struct firmware *asic_code;       /* Current ASIC code */
+       short dsp_code_to_load;         /* DSP code to load */
+       short asic_code;                /* Current ASIC code */
        u32 comm_page_phys;                     /* Physical address of the
                                                 * memory seen by DSP */
        volatile u32 __iomem *dsp_registers;    /* DSP's register base */
        u32 active_mask;                        /* Chs. active mask or
                                                 * punks out */
+#ifdef CONFIG_PM
+       const struct firmware *fw_cache[8];     /* Cached firmwares */
+#endif
 
 #ifdef ECHOCARD_HAS_MIDI
        u16 mtc_state;                          /* State for MIDI input parsing state machine */
@@ -464,11 +467,13 @@ static int load_firmware(struct echoaudio *chip);
 static int wait_handshake(struct echoaudio *chip);
 static int send_vector(struct echoaudio *chip, u32 command);
 static int get_firmware(const struct firmware **fw_entry,
-                       const struct firmware *frm, struct echoaudio *chip);
+                       struct echoaudio *chip, const short fw_index);
 static void free_firmware(const struct firmware *fw_entry);
 
 #ifdef ECHOCARD_HAS_MIDI
 static int enable_midi_input(struct echoaudio *chip, char enable);
+static void snd_echo_midi_output_trigger(
+                       struct snd_rawmidi_substream *substream, int up);
 static int midi_service_irq(struct echoaudio *chip);
 static int __devinit snd_echo_midi_create(struct snd_card *card,
                                          struct echoaudio *chip);
index e32a748979210098c6282bfb9879d4d8cf89d504..658db44ef74668b3583b4c11d4e0518be6b02743 100644 (file)
@@ -227,12 +227,11 @@ static int load_asic(struct echoaudio *chip)
        /* Give the DSP a few milliseconds to settle down */
        mdelay(2);
 
-       err = load_asic_generic(chip, DSP_FNC_LOAD_3G_ASIC,
-                               &card_fw[FW_3G_ASIC]);
+       err = load_asic_generic(chip, DSP_FNC_LOAD_3G_ASIC, FW_3G_ASIC);
        if (err < 0)
                return err;
 
-       chip->asic_code = &card_fw[FW_3G_ASIC];
+       chip->asic_code = FW_3G_ASIC;
 
        /* Now give the new ASIC some time to set up */
        msleep(1000);
index 4df51ef5e09533231100d94aa1bc35404e992df3..64417a7332200a8dda0acf4adf7ec36877d0719e 100644 (file)
@@ -175,15 +175,15 @@ static inline int check_asic_status(struct echoaudio *chip)
 #ifdef ECHOCARD_HAS_ASIC
 
 /* Load ASIC code - done after the DSP is loaded */
-static int load_asic_generic(struct echoaudio *chip, u32 cmd,
-                            const struct firmware *asic)
+static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic)
 {
        const struct firmware *fw;
        int err;
        u32 i, size;
        u8 *code;
 
-       if ((err = get_firmware(&fw, asic, chip)) < 0) {
+       err = get_firmware(&fw, chip, asic);
+       if (err < 0) {
                snd_printk(KERN_WARNING "Firmware not found !\n");
                return err;
        }
@@ -245,7 +245,8 @@ static int install_resident_loader(struct echoaudio *chip)
                return 0;
        }
 
-       if ((i = get_firmware(&fw, &card_fw[FW_361_LOADER], chip)) < 0) {
+       i = get_firmware(&fw, chip, FW_361_LOADER);
+       if (i < 0) {
                snd_printk(KERN_WARNING "Firmware not found !\n");
                return i;
        }
@@ -485,7 +486,8 @@ static int load_firmware(struct echoaudio *chip)
                chip->dsp_code = NULL;
        }
 
-       if ((err = get_firmware(&fw, chip->dsp_code_to_load, chip)) < 0)
+       err = get_firmware(&fw, chip, chip->dsp_code_to_load);
+       if (err < 0)
                return err;
        err = load_dsp(chip, (u16 *)fw->data);
        free_firmware(fw);
@@ -495,9 +497,6 @@ static int load_firmware(struct echoaudio *chip)
        if ((box_type = load_asic(chip)) < 0)
                return box_type;        /* error */
 
-       if ((err = restore_dsp_rettings(chip)) < 0)
-               return err;
-
        return box_type;
 }
 
@@ -657,51 +656,106 @@ static void get_audio_meters(struct echoaudio *chip, long *meters)
 
 static int restore_dsp_rettings(struct echoaudio *chip)
 {
-       int err;
+       int i, o, err;
        DE_INIT(("restore_dsp_settings\n"));
 
        if ((err = check_asic_status(chip)) < 0)
                return err;
 
-       /* Gina20/Darla20 only. Should be harmless for other cards. */
+       /* Gina20/Darla20 only. Should be harmless for other cards. */
        chip->comm_page->gd_clock_state = GD_CLOCK_UNDEF;
        chip->comm_page->gd_spdif_status = GD_SPDIF_STATUS_UNDEF;
        chip->comm_page->handshake = 0xffffffff;
 
-       if ((err = set_sample_rate(chip, chip->sample_rate)) < 0)
+       /* Restore output busses */
+       for (i = 0; i < num_busses_out(chip); i++) {
+               err = set_output_gain(chip, i, chip->output_gain[i]);
+               if (err < 0)
+                       return err;
+       }
+
+#ifdef ECHOCARD_HAS_VMIXER
+       for (i = 0; i < num_pipes_out(chip); i++)
+               for (o = 0; o < num_busses_out(chip); o++) {
+                       err = set_vmixer_gain(chip, o, i,
+                                               chip->vmixer_gain[o][i]);
+                       if (err < 0)
+                               return err;
+               }
+       if (update_vmixer_level(chip) < 0)
+               return -EIO;
+#endif /* ECHOCARD_HAS_VMIXER */
+
+#ifdef ECHOCARD_HAS_MONITOR
+       for (o = 0; o < num_busses_out(chip); o++)
+               for (i = 0; i < num_busses_in(chip); i++) {
+                       err = set_monitor_gain(chip, o, i,
+                                               chip->monitor_gain[o][i]);
+                       if (err < 0)
+                               return err;
+               }
+#endif /* ECHOCARD_HAS_MONITOR */
+
+#ifdef ECHOCARD_HAS_INPUT_GAIN
+       for (i = 0; i < num_busses_in(chip); i++) {
+               err = set_input_gain(chip, i, chip->input_gain[i]);
+               if (err < 0)
+                       return err;
+       }
+#endif /* ECHOCARD_HAS_INPUT_GAIN */
+
+       err = update_output_line_level(chip);
+       if (err < 0)
                return err;
 
-       if (chip->meters_enabled)
-               if (send_vector(chip, DSP_VC_METERS_ON) < 0)
-                       return -EIO;
+       err = update_input_line_level(chip);
+       if (err < 0)
+               return err;
 
-#ifdef ECHOCARD_HAS_EXTERNAL_CLOCK
-       if (set_input_clock(chip, chip->input_clock) < 0)
+       err = set_sample_rate(chip, chip->sample_rate);
+       if (err < 0)
+               return err;
+
+       if (chip->meters_enabled) {
+               err = send_vector(chip, DSP_VC_METERS_ON);
+               if (err < 0)
+                       return err;
+       }
+
+#ifdef ECHOCARD_HAS_DIGITAL_MODE_SWITCH
+       if (set_digital_mode(chip, chip->digital_mode) < 0)
                return -EIO;
 #endif
 
-#ifdef ECHOCARD_HAS_OUTPUT_CLOCK_SWITCH
-       if (set_output_clock(chip, chip->output_clock) < 0)
+#ifdef ECHOCARD_HAS_DIGITAL_IO
+       if (set_professional_spdif(chip, chip->professional_spdif) < 0)
                return -EIO;
 #endif
 
-       if (update_output_line_level(chip) < 0)
+#ifdef ECHOCARD_HAS_PHANTOM_POWER
+       if (set_phantom_power(chip, chip->phantom_power) < 0)
                return -EIO;
+#endif
 
-       if (update_input_line_level(chip) < 0)
+#ifdef ECHOCARD_HAS_EXTERNAL_CLOCK
+       /* set_input_clock() also restores automute setting */
+       if (set_input_clock(chip, chip->input_clock) < 0)
                return -EIO;
+#endif
 
-#ifdef ECHOCARD_HAS_VMIXER
-       if (update_vmixer_level(chip) < 0)
+#ifdef ECHOCARD_HAS_OUTPUT_CLOCK_SWITCH
+       if (set_output_clock(chip, chip->output_clock) < 0)
                return -EIO;
 #endif
 
        if (wait_handshake(chip) < 0)
                return -EIO;
        clear_handshake(chip);
+       if (send_vector(chip, DSP_VC_UPDATE_FLAGS) < 0)
+               return -EIO;
 
        DE_INIT(("restore_dsp_rettings done\n"));
-       return send_vector(chip, DSP_VC_UPDATE_FLAGS);
+       return 0;
 }
 
 
@@ -918,9 +972,6 @@ static int init_dsp_comm_page(struct echoaudio *chip)
        chip->card_name = ECHOCARD_NAME;
        chip->bad_board = TRUE; /* Set TRUE until DSP loaded */
        chip->dsp_code = NULL;  /* Current DSP code not loaded */
-       chip->digital_mode = DIGITAL_MODE_NONE;
-       chip->input_clock = ECHO_CLOCK_INTERNAL;
-       chip->output_clock = ECHO_CLOCK_WORD;
        chip->asic_loaded = FALSE;
        memset(chip->comm_page, 0, sizeof(struct comm_page));
 
@@ -931,7 +982,6 @@ static int init_dsp_comm_page(struct echoaudio *chip)
        chip->comm_page->midi_out_free_count =
                cpu_to_le32(DSP_MIDI_OUT_FIFO_SIZE);
        chip->comm_page->sample_rate = cpu_to_le32(44100);
-       chip->sample_rate = 44100;
 
        /* Set line levels so we don't blast any inputs on startup */
        memset(chip->comm_page->monitors, ECHOGAIN_MUTED, MONITOR_ARRAY_SIZE);
@@ -942,50 +992,21 @@ static int init_dsp_comm_page(struct echoaudio *chip)
 
 
 
-/* This function initializes the several volume controls for busses and pipes.
-This MUST be called after the DSP is up and running ! */
+/* This function initializes the chip structure with default values, ie. all
+ * muted and internal clock source. Then it copies the settings to the DSP.
+ * This MUST be called after the DSP is up and running !
+ */
 static int init_line_levels(struct echoaudio *chip)
 {
-       int st, i, o;
-
        DE_INIT(("init_line_levels\n"));
-
-       /* Mute output busses */
-       for (i = 0; i < num_busses_out(chip); i++)
-               if ((st = set_output_gain(chip, i, ECHOGAIN_MUTED)))
-                       return st;
-       if ((st = update_output_line_level(chip)))
-               return st;
-
-#ifdef ECHOCARD_HAS_VMIXER
-       /* Mute the Vmixer */
-       for (i = 0; i < num_pipes_out(chip); i++)
-               for (o = 0; o < num_busses_out(chip); o++)
-                       if ((st = set_vmixer_gain(chip, o, i, ECHOGAIN_MUTED)))
-                               return st;
-       if ((st = update_vmixer_level(chip)))
-               return st;
-#endif /* ECHOCARD_HAS_VMIXER */
-
-#ifdef ECHOCARD_HAS_MONITOR
-       /* Mute the monitor mixer */
-       for (o = 0; o < num_busses_out(chip); o++)
-               for (i = 0; i < num_busses_in(chip); i++)
-                       if ((st = set_monitor_gain(chip, o, i, ECHOGAIN_MUTED)))
-                               return st;
-       if ((st = update_output_line_level(chip)))
-               return st;
-#endif /* ECHOCARD_HAS_MONITOR */
-
-#ifdef ECHOCARD_HAS_INPUT_GAIN
-       for (i = 0; i < num_busses_in(chip); i++)
-               if ((st = set_input_gain(chip, i, ECHOGAIN_MUTED)))
-                       return st;
-       if ((st = update_input_line_level(chip)))
-               return st;
-#endif /* ECHOCARD_HAS_INPUT_GAIN */
-
-       return 0;
+       memset(chip->output_gain, ECHOGAIN_MUTED, sizeof(chip->output_gain));
+       memset(chip->input_gain, ECHOGAIN_MUTED, sizeof(chip->input_gain));
+       memset(chip->monitor_gain, ECHOGAIN_MUTED, sizeof(chip->monitor_gain));
+       memset(chip->vmixer_gain, ECHOGAIN_MUTED, sizeof(chip->vmixer_gain));
+       chip->input_clock = ECHO_CLOCK_INTERNAL;
+       chip->output_clock = ECHO_CLOCK_WORD;
+       chip->sample_rate = 44100;
+       return restore_dsp_rettings(chip);
 }
 
 
index c0e64b8f52a40577834d29da28f42443667a59ff..2364f8a1bc21509e678c6d09eab207f2efa0e0c7 100644 (file)
@@ -67,7 +67,7 @@ static const struct firmware card_fw[] = {
        {0, "gina20_dsp.fw"}
 };
 
-static struct pci_device_id snd_echo_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = {
        {0x1057, 0x1801, 0xECC0, 0x0020, 0, 0, 0},      /* DSP 56301 Gina20 rev.0 */
        {0,}
 };
index 3f1e7475faea916203d6c3af085ce5bb6fd1300e..d1615a0579d17f50fe9563e837631ab89161b6ab 100644 (file)
@@ -49,7 +49,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        chip->device_id = device_id;
        chip->subdevice_id = subdevice_id;
        chip->bad_board = TRUE;
-       chip->dsp_code_to_load = &card_fw[FW_GINA20_DSP];
+       chip->dsp_code_to_load = FW_GINA20_DSP;
        chip->spdif_status = GD_SPDIF_STATUS_UNDEF;
        chip->clock_state = GD_CLOCK_UNDEF;
        /* Since this card has no ASIC, mark it as loaded so everything
@@ -62,17 +62,20 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
                return err;
        chip->bad_board = FALSE;
 
-       if ((err = init_line_levels(chip)) < 0)
-               return err;
-
-       err = set_professional_spdif(chip, TRUE);
-
        DE_INIT(("init_hw done\n"));
        return err;
 }
 
 
 
+static int set_mixer_defaults(struct echoaudio *chip)
+{
+       chip->professional_spdif = FALSE;
+       return init_line_levels(chip);
+}
+
+
+
 static u32 detect_input_clocks(const struct echoaudio *chip)
 {
        u32 clocks_from_dsp, clock_bits;
index c36a78dd0b5e373d6202c97cc3dd54833e122583..616b55825a194af53d8bee426987422bd07ba0f1 100644 (file)
@@ -85,7 +85,7 @@ static const struct firmware card_fw[] = {
        {0, "gina24_361_asic.fw"}
 };
 
-static struct pci_device_id snd_echo_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = {
        {0x1057, 0x1801, 0xECC0, 0x0050, 0, 0, 0},      /* DSP 56301 Gina24 rev.0 */
        {0x1057, 0x1801, 0xECC0, 0x0051, 0, 0, 0},      /* DSP 56301 Gina24 rev.1 */
        {0x1057, 0x3410, 0xECC0, 0x0050, 0, 0, 0},      /* DSP 56361 Gina24 rev.0 */
index 2fef37a2a5b96693abc5988fc420a7827d36b8ae..98f7cfa81b5f3bb0fcbd660c3b1f9527e390bde7 100644 (file)
@@ -33,8 +33,7 @@ static int write_control_reg(struct echoaudio *chip, u32 value, char force);
 static int set_input_clock(struct echoaudio *chip, u16 clock);
 static int set_professional_spdif(struct echoaudio *chip, char prof);
 static int set_digital_mode(struct echoaudio *chip, u8 mode);
-static int load_asic_generic(struct echoaudio *chip, u32 cmd,
-                            const struct firmware *asic);
+static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic);
 static int check_asic_status(struct echoaudio *chip);
 
 
@@ -58,19 +57,16 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
                ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF |
                ECHO_CLOCK_BIT_ESYNC | ECHO_CLOCK_BIT_ESYNC96 |
                ECHO_CLOCK_BIT_ADAT;
-       chip->professional_spdif = FALSE;
-       chip->digital_in_automute = TRUE;
-       chip->digital_mode = DIGITAL_MODE_SPDIF_RCA;
 
        /* Gina24 comes in both '301 and '361 flavors */
        if (chip->device_id == DEVICE_ID_56361) {
-               chip->dsp_code_to_load = &card_fw[FW_GINA24_361_DSP];
+               chip->dsp_code_to_load = FW_GINA24_361_DSP;
                chip->digital_modes =
                        ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA |
                        ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL |
                        ECHOCAPS_HAS_DIGITAL_MODE_ADAT;
        } else {
-               chip->dsp_code_to_load = &card_fw[FW_GINA24_301_DSP];
+               chip->dsp_code_to_load = FW_GINA24_301_DSP;
                chip->digital_modes =
                        ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA |
                        ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL |
@@ -82,19 +78,22 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
                return err;
        chip->bad_board = FALSE;
 
-       if ((err = init_line_levels(chip)) < 0)
-               return err;
-       err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA);
-       if (err < 0)
-               return err;
-       err = set_professional_spdif(chip, TRUE);
-
        DE_INIT(("init_hw done\n"));
        return err;
 }
 
 
 
+static int set_mixer_defaults(struct echoaudio *chip)
+{
+       chip->digital_mode = DIGITAL_MODE_SPDIF_RCA;
+       chip->professional_spdif = FALSE;
+       chip->digital_in_automute = TRUE;
+       return init_line_levels(chip);
+}
+
+
+
 static u32 detect_input_clocks(const struct echoaudio *chip)
 {
        u32 clocks_from_dsp, clock_bits;
@@ -125,7 +124,7 @@ static int load_asic(struct echoaudio *chip)
 {
        u32 control_reg;
        int err;
-       const struct firmware *fw;
+       short asic;
 
        if (chip->asic_loaded)
                return 1;
@@ -135,14 +134,15 @@ static int load_asic(struct echoaudio *chip)
 
        /* Pick the correct ASIC for '301 or '361 Gina24 */
        if (chip->device_id == DEVICE_ID_56361)
-               fw = &card_fw[FW_GINA24_361_ASIC];
+               asic = FW_GINA24_361_ASIC;
        else
-               fw = &card_fw[FW_GINA24_301_ASIC];
+               asic = FW_GINA24_301_ASIC;
 
-       if ((err = load_asic_generic(chip, DSP_FNC_LOAD_GINA24_ASIC, fw)) < 0)
+       err = load_asic_generic(chip, DSP_FNC_LOAD_GINA24_ASIC, asic);
+       if (err < 0)
                return err;
 
-       chip->asic_code = fw;
+       chip->asic_code = asic;
 
        /* Now give the new ASIC a little time to set up */
        mdelay(10);
index 0a58a7c1fd7cc69fc02aa042a356b4ad47b00ae4..776175c0bdad10c4bb86b014274dc349aac5db02 100644 (file)
@@ -68,7 +68,7 @@ static const struct firmware card_fw[] = {
        {0, "indigo_dsp.fw"}
 };
 
-static struct pci_device_id snd_echo_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = {
        {0x1057, 0x3410, 0xECC0, 0x0090, 0, 0, 0},      /* Indigo */
        {0,}
 };
index 0b2cd9c8627750f0b2addbc5c8005756d9edb1aa..5e85f14fe5a8c83e78e3d59b5321674f3157136f 100644 (file)
@@ -50,7 +50,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        chip->device_id = device_id;
        chip->subdevice_id = subdevice_id;
        chip->bad_board = TRUE;
-       chip->dsp_code_to_load = &card_fw[FW_INDIGO_DSP];
+       chip->dsp_code_to_load = FW_INDIGO_DSP;
        /* Since this card has no ASIC, mark it as loaded so everything
           works OK */
        chip->asic_loaded = TRUE;
@@ -60,15 +60,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
                return err;
        chip->bad_board = FALSE;
 
-       if ((err = init_line_levels(chip)) < 0)
-               return err;
-
        DE_INIT(("init_hw done\n"));
        return err;
 }
 
 
 
+static int set_mixer_defaults(struct echoaudio *chip)
+{
+       return init_line_levels(chip);
+}
+
+
+
 static u32 detect_input_clocks(const struct echoaudio *chip)
 {
        return ECHO_CLOCK_BIT_INTERNAL;
index 9ab625e15652512305bf1b3089a319bbe2efa2a0..2e4ab3e34a7454e1053d131d768aadc8a12d4aab 100644 (file)
@@ -61,6 +61,7 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
 
        control_reg |= clock;
        if (control_reg != old_control_reg) {
+               DE_ACT(("set_sample_rate: %d clock %d\n", rate, clock));
                chip->comm_page->control_register = cpu_to_le32(control_reg);
                chip->sample_rate = rate;
                clear_handshake(chip);
index 2db24d29332bea8eed11bc0e0311df1756666e11..8816b0bd2ba61102ea2b922d88f61efcccfb56c2 100644 (file)
@@ -68,7 +68,7 @@ static const struct firmware card_fw[] = {
        {0, "indigo_dj_dsp.fw"}
 };
 
-static struct pci_device_id snd_echo_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = {
        {0x1057, 0x3410, 0xECC0, 0x00B0, 0, 0, 0},      /* Indigo DJ*/
        {0,}
 };
index 08392916691e365d53422f660cb5ac54e7c36b58..68f3c8ccc1bf83375bb6873bbe62c3237b415e11 100644 (file)
@@ -50,7 +50,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        chip->device_id = device_id;
        chip->subdevice_id = subdevice_id;
        chip->bad_board = TRUE;
-       chip->dsp_code_to_load = &card_fw[FW_INDIGO_DJ_DSP];
+       chip->dsp_code_to_load = FW_INDIGO_DJ_DSP;
        /* Since this card has no ASIC, mark it as loaded so everything
           works OK */
        chip->asic_loaded = TRUE;
@@ -60,15 +60,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
                return err;
        chip->bad_board = FALSE;
 
-       if ((err = init_line_levels(chip)) < 0)
-               return err;
-
        DE_INIT(("init_hw done\n"));
        return err;
 }
 
 
 
+static int set_mixer_defaults(struct echoaudio *chip)
+{
+       return init_line_levels(chip);
+}
+
+
+
 static u32 detect_input_clocks(const struct echoaudio *chip)
 {
        return ECHO_CLOCK_BIT_INTERNAL;
index 2e44316530a298d39e1295df8d1f3f9edc585ef0..b1e3652f2f485669874130be56287e97080133f7 100644 (file)
@@ -68,7 +68,7 @@ static const struct firmware card_fw[] = {
        {0, "indigo_djx_dsp.fw"}
 };
 
-static struct pci_device_id snd_echo_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = {
        {0x1057, 0x3410, 0xECC0, 0x00E0, 0, 0, 0},      /* Indigo DJx*/
        {0,}
 };
index f591fc2ed960c4904d4a05a8fe5140fbbec774e9..bb9632c752a953e873bb0d85c32efa80c7021ab1 100644 (file)
@@ -48,7 +48,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        chip->device_id = device_id;
        chip->subdevice_id = subdevice_id;
        chip->bad_board = TRUE;
-       chip->dsp_code_to_load = &card_fw[FW_INDIGO_DJX_DSP];
+       chip->dsp_code_to_load = FW_INDIGO_DJX_DSP;
        /* Since this card has no ASIC, mark it as loaded so everything
           works OK */
        chip->asic_loaded = TRUE;
@@ -59,10 +59,13 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
                return err;
        chip->bad_board = FALSE;
 
-       err = init_line_levels(chip);
-       if (err < 0)
-               return err;
-
        DE_INIT(("init_hw done\n"));
        return err;
 }
+
+
+
+static int set_mixer_defaults(struct echoaudio *chip)
+{
+       return init_line_levels(chip);
+}
index a60c0a0a89b737470da2b6d650d7c2cbb352fc7e..1035125336d6f89a0f36bc63d1bd5c8e67fae735 100644 (file)
@@ -69,7 +69,7 @@ static const struct firmware card_fw[] = {
        {0, "indigo_io_dsp.fw"}
 };
 
-static struct pci_device_id snd_echo_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = {
        {0x1057, 0x3410, 0xECC0, 0x00A0, 0, 0, 0},      /* Indigo IO*/
        {0,}
 };
index 0604c8a85223bc7b0ceacfc6f60b3171193b65aa..beb9a5b69892e496a9717b917263a7fcef230cab 100644 (file)
@@ -50,7 +50,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        chip->device_id = device_id;
        chip->subdevice_id = subdevice_id;
        chip->bad_board = TRUE;
-       chip->dsp_code_to_load = &card_fw[FW_INDIGO_IO_DSP];
+       chip->dsp_code_to_load = FW_INDIGO_IO_DSP;
        /* Since this card has no ASIC, mark it as loaded so everything
           works OK */
        chip->asic_loaded = TRUE;
@@ -60,15 +60,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
                return err;
        chip->bad_board = FALSE;
 
-       if ((err = init_line_levels(chip)) < 0)
-               return err;
-
        DE_INIT(("init_hw done\n"));
        return err;
 }
 
 
 
+static int set_mixer_defaults(struct echoaudio *chip)
+{
+       return init_line_levels(chip);
+}
+
+
+
 static u32 detect_input_clocks(const struct echoaudio *chip)
 {
        return ECHO_CLOCK_BIT_INTERNAL;
index eb3819f9654a6630184b06436f9f9d1f5f9e7c9b..60b7cb2753cfd2fd1968bc6f978e95b542f62cfc 100644 (file)
@@ -69,7 +69,7 @@ static const struct firmware card_fw[] = {
        {0, "indigo_iox_dsp.fw"}
 };
 
-static struct pci_device_id snd_echo_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = {
        {0x1057, 0x3410, 0xECC0, 0x00D0, 0, 0, 0},      /* Indigo IOx */
        {0,}
 };
index f357521c79e6ebc5bea7139d2f521f4ec31a1e8c..394c6e76bcbcba5a377d7d7ed38e8957ccf1f2ed 100644 (file)
@@ -48,7 +48,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        chip->device_id = device_id;
        chip->subdevice_id = subdevice_id;
        chip->bad_board = TRUE;
-       chip->dsp_code_to_load = &card_fw[FW_INDIGO_IOX_DSP];
+       chip->dsp_code_to_load = FW_INDIGO_IOX_DSP;
        /* Since this card has no ASIC, mark it as loaded so everything
           works OK */
        chip->asic_loaded = TRUE;
@@ -59,10 +59,13 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
                return err;
        chip->bad_board = FALSE;
 
-       err = init_line_levels(chip);
-       if (err < 0)
-               return err;
-
        DE_INIT(("init_hw done\n"));
        return err;
 }
+
+
+
+static int set_mixer_defaults(struct echoaudio *chip)
+{
+       return init_line_levels(chip);
+}
index 506194688995ddab5499c556f5d425c8b908511a..8c3f5c5b53013a879b5848663d7aadab209e2023 100644 (file)
@@ -76,7 +76,7 @@ static const struct firmware card_fw[] = {
        {0, "layla20_asic.fw"}
 };
 
-static struct pci_device_id snd_echo_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = {
        {0x1057, 0x1801, 0xECC0, 0x0030, 0, 0, 0},      /* DSP 56301 Layla20 rev.0 */
        {0x1057, 0x1801, 0xECC0, 0x0031, 0, 0, 0},      /* DSP 56301 Layla20 rev.1 */
        {0,}
index 83750e9fd7b4a3cc0290498ac1a267ee5c5da30f..53ce9460504413a0fabbc705623a0832cb8f188d 100644 (file)
@@ -31,8 +31,7 @@
 
 static int read_dsp(struct echoaudio *chip, u32 *data);
 static int set_professional_spdif(struct echoaudio *chip, char prof);
-static int load_asic_generic(struct echoaudio *chip, u32 cmd,
-                            const struct firmware *asic);
+static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic);
 static int check_asic_status(struct echoaudio *chip);
 static int update_flags(struct echoaudio *chip);
 
@@ -54,7 +53,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        chip->subdevice_id = subdevice_id;
        chip->bad_board = TRUE;
        chip->has_midi = TRUE;
-       chip->dsp_code_to_load = &card_fw[FW_LAYLA20_DSP];
+       chip->dsp_code_to_load = FW_LAYLA20_DSP;
        chip->input_clock_types =
                ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF |
                ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_SUPER;
@@ -65,17 +64,20 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
                return err;
        chip->bad_board = FALSE;
 
-       if ((err = init_line_levels(chip)) < 0)
-               return err;
-
-       err = set_professional_spdif(chip, TRUE);
-
        DE_INIT(("init_hw done\n"));
        return err;
 }
 
 
 
+static int set_mixer_defaults(struct echoaudio *chip)
+{
+       chip->professional_spdif = FALSE;
+       return init_line_levels(chip);
+}
+
+
+
 static u32 detect_input_clocks(const struct echoaudio *chip)
 {
        u32 clocks_from_dsp, clock_bits;
@@ -144,7 +146,7 @@ static int load_asic(struct echoaudio *chip)
                return 0;
 
        err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA_ASIC,
-                               &card_fw[FW_LAYLA20_ASIC]);
+                               FW_LAYLA20_ASIC);
        if (err < 0)
                return err;
 
index e09e3ea7781e4c6a87247b1ae8adb2f176db49dc..ed1cc0abc2b82cf2a8523ad4711c3b8cfce90f0b 100644 (file)
@@ -87,7 +87,7 @@ static const struct firmware card_fw[] = {
        {0, "layla24_2S_asic.fw"}
 };
 
-static struct pci_device_id snd_echo_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = {
        {0x1057, 0x3410, 0xECC0, 0x0060, 0, 0, 0},      /* DSP 56361 Layla24 rev.0 */
        {0,}
 };
index d61b5cbcccad4235314d6d0bd05ee93e82ed282f..8c041647f285e0fe44afb3eb853c96c6dd27dac7 100644 (file)
@@ -32,8 +32,7 @@ static int write_control_reg(struct echoaudio *chip, u32 value, char force);
 static int set_input_clock(struct echoaudio *chip, u16 clock);
 static int set_professional_spdif(struct echoaudio *chip, char prof);
 static int set_digital_mode(struct echoaudio *chip, u8 mode);
-static int load_asic_generic(struct echoaudio *chip, u32 cmd,
-                            const struct firmware *asic);
+static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic);
 static int check_asic_status(struct echoaudio *chip);
 
 
@@ -54,7 +53,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        chip->subdevice_id = subdevice_id;
        chip->bad_board = TRUE;
        chip->has_midi = TRUE;
-       chip->dsp_code_to_load = &card_fw[FW_LAYLA24_DSP];
+       chip->dsp_code_to_load = FW_LAYLA24_DSP;
        chip->input_clock_types =
                ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF |
                ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_ADAT;
@@ -62,9 +61,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
                ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA |
                ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL |
                ECHOCAPS_HAS_DIGITAL_MODE_ADAT;
-       chip->digital_mode =            DIGITAL_MODE_SPDIF_RCA;
-       chip->professional_spdif = FALSE;
-       chip->digital_in_automute = TRUE;
 
        if ((err = load_firmware(chip)) < 0)
                return err;
@@ -73,17 +69,22 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        if ((err = init_line_levels(chip)) < 0)
                return err;
 
-       err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA);
-       if (err < 0)
-               return err;
-       err = set_professional_spdif(chip, TRUE);
-
        DE_INIT(("init_hw done\n"));
        return err;
 }
 
 
 
+static int set_mixer_defaults(struct echoaudio *chip)
+{
+       chip->digital_mode = DIGITAL_MODE_SPDIF_RCA;
+       chip->professional_spdif = FALSE;
+       chip->digital_in_automute = TRUE;
+       return init_line_levels(chip);
+}
+
+
+
 static u32 detect_input_clocks(const struct echoaudio *chip)
 {
        u32 clocks_from_dsp, clock_bits;
@@ -123,18 +124,18 @@ static int load_asic(struct echoaudio *chip)
 
        /* Load the ASIC for the PCI card */
        err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA24_PCI_CARD_ASIC,
-                               &card_fw[FW_LAYLA24_1_ASIC]);
+                               FW_LAYLA24_1_ASIC);
        if (err < 0)
                return err;
 
-       chip->asic_code = &card_fw[FW_LAYLA24_2S_ASIC];
+       chip->asic_code = FW_LAYLA24_2S_ASIC;
 
        /* Now give the new ASIC a little time to set up */
        mdelay(10);
 
        /* Do the external one */
        err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA24_EXTERNAL_ASIC,
-                               &card_fw[FW_LAYLA24_2S_ASIC]);
+                               FW_LAYLA24_2S_ASIC);
        if (err < 0)
                return FALSE;
 
@@ -299,7 +300,7 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
 /* Depending on what digital mode you want, Layla24 needs different ASICs
 loaded.  This function checks the ASIC needed for the new mode and sees
 if it matches the one already loaded. */
-static int switch_asic(struct echoaudio *chip, const struct firmware *asic)
+static int switch_asic(struct echoaudio *chip, short asic)
 {
        s8 *monitors;
 
@@ -335,7 +336,7 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
 {
        u32 control_reg;
        int err, incompatible_clock;
-       const struct firmware *asic;
+       short asic;
 
        /* Set clock to "internal" if it's not compatible with the new mode */
        incompatible_clock = FALSE;
@@ -344,12 +345,12 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
        case DIGITAL_MODE_SPDIF_RCA:
                if (chip->input_clock == ECHO_CLOCK_ADAT)
                        incompatible_clock = TRUE;
-               asic = &card_fw[FW_LAYLA24_2S_ASIC];
+               asic = FW_LAYLA24_2S_ASIC;
                break;
        case DIGITAL_MODE_ADAT:
                if (chip->input_clock == ECHO_CLOCK_SPDIF)
                        incompatible_clock = TRUE;
-               asic = &card_fw[FW_LAYLA24_2A_ASIC];
+               asic = FW_LAYLA24_2A_ASIC;
                break;
        default:
                DE_ACT(("Digital mode not supported: %d\n", mode));
index f05c8c097aa8196de2f9fe0a62e6e45e2efbd66c..cc2bbfc65327f23284a3000257aa261e497f2189 100644 (file)
@@ -77,7 +77,7 @@ static const struct firmware card_fw[] = {
        {0, "mia_dsp.fw"}
 };
 
-static struct pci_device_id snd_echo_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = {
        {0x1057, 0x3410, 0xECC0, 0x0080, 0, 0, 0},      /* DSP 56361 Mia rev.0 */
        {0x1057, 0x3410, 0xECC0, 0x0081, 0, 0, 0},      /* DSP 56361 Mia rev.1 */
        {0,}
index 551405114cbc67a33f04f0bf3fa37038ce1b32b7..6ebfa6e7ab9e28bd1301bd75ab0ff4334c7bd40a 100644 (file)
@@ -53,7 +53,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        chip->device_id = device_id;
        chip->subdevice_id = subdevice_id;
        chip->bad_board = TRUE;
-       chip->dsp_code_to_load = &card_fw[FW_MIA_DSP];
+       chip->dsp_code_to_load = FW_MIA_DSP;
        /* Since this card has no ASIC, mark it as loaded so everything
           works OK */
        chip->asic_loaded = TRUE;
@@ -66,15 +66,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
                return err;
        chip->bad_board = FALSE;
 
-       if ((err = init_line_levels(chip)))
-               return err;
-
        DE_INIT(("init_hw done\n"));
        return err;
 }
 
 
 
+static int set_mixer_defaults(struct echoaudio *chip)
+{
+       return init_line_levels(chip);
+}
+
+
+
 static u32 detect_input_clocks(const struct echoaudio *chip)
 {
        u32 clocks_from_dsp, clock_bits;
index b05bad944901b6662dbb19bc231260087e1c08b3..3e7e01824b4073febd740144f906a460d77670c9 100644 (file)
@@ -92,7 +92,7 @@ static const struct firmware card_fw[] = {
        {0, "mona_2_asic.fw"}
 };
 
-static struct pci_device_id snd_echo_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = {
        {0x1057, 0x1801, 0xECC0, 0x0070, 0, 0, 0},      /* DSP 56301 Mona rev.0 */
        {0x1057, 0x1801, 0xECC0, 0x0071, 0, 0, 0},      /* DSP 56301 Mona rev.1 */
        {0x1057, 0x1801, 0xECC0, 0x0072, 0, 0, 0},      /* DSP 56301 Mona rev.2 */
index eaa619bd2a0343f2d9a5e7a7c7c8b54585a9413c..6e6a7eb555b8103f455d5c65fd056d94f320917f 100644 (file)
@@ -33,8 +33,7 @@ static int write_control_reg(struct echoaudio *chip, u32 value, char force);
 static int set_input_clock(struct echoaudio *chip, u16 clock);
 static int set_professional_spdif(struct echoaudio *chip, char prof);
 static int set_digital_mode(struct echoaudio *chip, u8 mode);
-static int load_asic_generic(struct echoaudio *chip, u32 cmd,
-                            const struct firmware *asic);
+static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic);
 static int check_asic_status(struct echoaudio *chip);
 
 
@@ -64,32 +63,30 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
 
        /* Mona comes in both '301 and '361 flavors */
        if (chip->device_id == DEVICE_ID_56361)
-               chip->dsp_code_to_load = &card_fw[FW_MONA_361_DSP];
+               chip->dsp_code_to_load = FW_MONA_361_DSP;
        else
-               chip->dsp_code_to_load = &card_fw[FW_MONA_301_DSP];
-
-       chip->digital_mode = DIGITAL_MODE_SPDIF_RCA;
-       chip->professional_spdif = FALSE;
-       chip->digital_in_automute = TRUE;
+               chip->dsp_code_to_load = FW_MONA_301_DSP;
 
        if ((err = load_firmware(chip)) < 0)
                return err;
        chip->bad_board = FALSE;
 
-       if ((err = init_line_levels(chip)) < 0)
-               return err;
-
-       err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA);
-       if (err < 0)
-               return err;
-       err = set_professional_spdif(chip, TRUE);
-
        DE_INIT(("init_hw done\n"));
        return err;
 }
 
 
 
+static int set_mixer_defaults(struct echoaudio *chip)
+{
+       chip->digital_mode = DIGITAL_MODE_SPDIF_RCA;
+       chip->professional_spdif = FALSE;
+       chip->digital_in_automute = TRUE;
+       return init_line_levels(chip);
+}
+
+
+
 static u32 detect_input_clocks(const struct echoaudio *chip)
 {
        u32 clocks_from_dsp, clock_bits;
@@ -120,7 +117,7 @@ static int load_asic(struct echoaudio *chip)
 {
        u32 control_reg;
        int err;
-       const struct firmware *asic;
+       short asic;
 
        if (chip->asic_loaded)
                return 0;
@@ -128,9 +125,9 @@ static int load_asic(struct echoaudio *chip)
        mdelay(10);
 
        if (chip->device_id == DEVICE_ID_56361)
-               asic = &card_fw[FW_MONA_361_1_ASIC48];
+               asic = FW_MONA_361_1_ASIC48;
        else
-               asic = &card_fw[FW_MONA_301_1_ASIC48];
+               asic = FW_MONA_301_1_ASIC48;
 
        err = load_asic_generic(chip, DSP_FNC_LOAD_MONA_PCI_CARD_ASIC, asic);
        if (err < 0)
@@ -141,7 +138,7 @@ static int load_asic(struct echoaudio *chip)
 
        /* Do the external one */
        err = load_asic_generic(chip, DSP_FNC_LOAD_MONA_EXTERNAL_ASIC,
-                               &card_fw[FW_MONA_2_ASIC]);
+                               FW_MONA_2_ASIC);
        if (err < 0)
                return err;
 
@@ -165,22 +162,22 @@ loaded.  This function checks the ASIC needed for the new mode and sees
 if it matches the one already loaded. */
 static int switch_asic(struct echoaudio *chip, char double_speed)
 {
-       const struct firmware *asic;
        int err;
+       short asic;
 
        /* Check the clock detect bits to see if this is
        a single-speed clock or a double-speed clock; load
        a new ASIC if necessary. */
        if (chip->device_id == DEVICE_ID_56361) {
                if (double_speed)
-                       asic = &card_fw[FW_MONA_361_1_ASIC96];
+                       asic = FW_MONA_361_1_ASIC96;
                else
-                       asic = &card_fw[FW_MONA_361_1_ASIC48];
+                       asic = FW_MONA_361_1_ASIC48;
        } else {
                if (double_speed)
-                       asic = &card_fw[FW_MONA_301_1_ASIC96];
+                       asic = FW_MONA_301_1_ASIC96;
                else
-                       asic = &card_fw[FW_MONA_301_1_ASIC48];
+                       asic = FW_MONA_301_1_ASIC48;
        }
 
        if (asic != chip->asic_code) {
@@ -200,7 +197,7 @@ static int switch_asic(struct echoaudio *chip, char double_speed)
 static int set_sample_rate(struct echoaudio *chip, u32 rate)
 {
        u32 control_reg, clock;
-       const struct firmware *asic;
+       short asic;
        char force_write;
 
        /* Only set the clock for internal mode. */
@@ -218,14 +215,14 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
                if (chip->digital_mode == DIGITAL_MODE_ADAT)
                        return -EINVAL;
                if (chip->device_id == DEVICE_ID_56361)
-                       asic = &card_fw[FW_MONA_361_1_ASIC96];
+                       asic = FW_MONA_361_1_ASIC96;
                else
-                       asic = &card_fw[FW_MONA_301_1_ASIC96];
+                       asic = FW_MONA_301_1_ASIC96;
        } else {
                if (chip->device_id == DEVICE_ID_56361)
-                       asic = &card_fw[FW_MONA_361_1_ASIC48];
+                       asic = FW_MONA_361_1_ASIC48;
                else
-                       asic = &card_fw[FW_MONA_301_1_ASIC48];
+                       asic = FW_MONA_301_1_ASIC48;
        }
 
        force_write = 0;
@@ -410,8 +407,8 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
        case DIGITAL_MODE_ADAT:
                /* If the current ASIC is the 96KHz ASIC, switch the ASIC
                   and set to 48 KHz */
-               if (chip->asic_code == &card_fw[FW_MONA_361_1_ASIC96] ||
-                   chip->asic_code == &card_fw[FW_MONA_301_1_ASIC96]) {
+               if (chip->asic_code == FW_MONA_361_1_ASIC96 ||
+                   chip->asic_code == FW_MONA_301_1_ASIC96) {
                        set_sample_rate(chip, 48000);
                }
                control_reg |= GML_ADAT_MODE;
index 168af67d938e1415993b29eb166763327ec0048b..4203782d7cb79bec7e7bf47157b32ee04de1efee 100644 (file)
@@ -76,7 +76,7 @@ MODULE_PARM_DESC(subsystem, "Force card subsystem model.");
 /*
  * Class 0401: 1102:0008 (rev 00) Subsystem: 1102:1001 -> Audigy2 Value  Model:SB0400
  */
-static struct pci_device_id snd_emu10k1_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_emu10k1_ids) = {
        { PCI_VDEVICE(CREATIVE, 0x0002), 0 },   /* EMU10K1 */
        { PCI_VDEVICE(CREATIVE, 0x0004), 1 },   /* Audigy */
        { PCI_VDEVICE(CREATIVE, 0x0008), 1 },   /* Audigy 2 Value SB0400 */
index 1d369ff73805658967e87a52809168936d97f4da..df47f738098df265e1d702efb5adaec7cd49c022 100644 (file)
@@ -1605,7 +1605,7 @@ static void __devexit snd_emu10k1x_remove(struct pci_dev *pci)
 }
 
 // PCI IDs
-static struct pci_device_id snd_emu10k1x_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_emu10k1x_ids) = {
        { PCI_VDEVICE(CREATIVE, 0x0006), 0 },   /* Dell OEM version (EMU10K1) */
        { 0, }
 };
index 2b82c5c723e159a1f393724dbca259f12d755050..c7fba53798138b9ec7604fab68d0861c7434db02 100644 (file)
@@ -443,7 +443,7 @@ struct ensoniq {
 
 static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id);
 
-static struct pci_device_id snd_audiopci_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_audiopci_ids) = {
 #ifdef CHIP1370
        { PCI_VDEVICE(ENSONIQ, 0x5000), 0, },   /* ES1370 */
 #endif
index fb83e1ffa5cb5e99ed3b697bedaf5fe66ff78e91..553b752172593fc377d5da54d5267f47ece5ed3f 100644 (file)
@@ -243,7 +243,7 @@ struct es1938 {
 
 static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id);
 
-static struct pci_device_id snd_es1938_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_es1938_ids) = {
        { PCI_VDEVICE(ESS, 0x1969), 0, },   /* Solo-1 */
        { 0, }
 };
index a11f453a6b6d697614943024696de4b5019d6339..ecaea9fb48ec24328ac634a6441ad3538abc5207 100644 (file)
@@ -551,7 +551,7 @@ struct es1968 {
 
 static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id);
 
-static struct pci_device_id snd_es1968_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_es1968_ids) = {
        /* Maestro 1 */
         { 0x1285, 0x0100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, TYPE_MAESTRO },
        /* Maestro 2 */
index 83508b3964fb7c91329bff336a3a276f42e0e7ba..e1baad74ea4b4f8a2ae80894c330c0a46026694d 100644 (file)
@@ -205,7 +205,7 @@ struct fm801 {
 #endif
 };
 
-static struct pci_device_id snd_fm801_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_fm801_ids) = {
        { 0x1319, 0x0801, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, },   /* FM801 */
        { 0x5213, 0x0510, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, },   /* Gallant Odyssey Sound 4 */
        { 0, }
index f98b47cd6cfb38fc97335c3788a8f7f5cc3afca1..76d3c4c049dbea96edbbf7db4faf78e799f9da96 100644 (file)
@@ -824,6 +824,9 @@ int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list,
        struct hda_pincfg *pin;
        unsigned int oldcfg;
 
+       if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
+               return -EINVAL;
+
        oldcfg = snd_hda_codec_get_pincfg(codec, nid);
        pin = look_up_pincfg(codec, list, nid);
        if (!pin) {
@@ -899,6 +902,25 @@ static void restore_pincfgs(struct hda_codec *codec)
        }
 }
 
+/**
+ * snd_hda_shutup_pins - Shut up all pins
+ * @codec: the HDA codec
+ *
+ * Clear all pin controls to shup up before suspend for avoiding click noise.
+ * The controls aren't cached so that they can be resumed properly.
+ */
+void snd_hda_shutup_pins(struct hda_codec *codec)
+{
+       int i;
+       for (i = 0; i < codec->init_pins.used; i++) {
+               struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i);
+               /* use read here for syncing after issuing each verb */
+               snd_hda_codec_read(codec, pin->nid, 0,
+                                  AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+       }
+}
+EXPORT_SYMBOL_HDA(snd_hda_shutup_pins);
+
 static void init_hda_cache(struct hda_cache_rec *cache,
                           unsigned int record_size);
 static void free_hda_cache(struct hda_cache_rec *cache);
@@ -931,6 +953,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
 #endif
        list_del(&codec->list);
        snd_array_free(&codec->mixers);
+       snd_array_free(&codec->nids);
        codec->bus->caddr_tbl[codec->addr] = NULL;
        if (codec->patch_ops.free)
                codec->patch_ops.free(codec);
@@ -985,7 +1008,8 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr
        mutex_init(&codec->control_mutex);
        init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
        init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
-       snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 60);
+       snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 32);
+       snd_array_init(&codec->nids, sizeof(struct hda_nid_item), 32);
        snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16);
        snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16);
        if (codec->bus->modelname) {
@@ -1708,7 +1732,7 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
 EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl);
 
 /**
- * snd_hda_ctl-add - Add a control element and assign to the codec
+ * snd_hda_ctl_add - Add a control element and assign to the codec
  * @codec: HD-audio codec
  * @nid: corresponding NID (optional)
  * @kctl: the control element to assign
@@ -1723,19 +1747,25 @@ EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl);
  *
  * snd_hda_ctl_add() checks the control subdev id field whether
  * #HDA_SUBDEV_NID_FLAG bit is set.  If set (and @nid is zero), the lower
- * bits value is taken as the NID to assign.
+ * bits value is taken as the NID to assign. The #HDA_NID_ITEM_AMP bit
+ * specifies if kctl->private_value is a HDA amplifier value.
  */
 int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
                    struct snd_kcontrol *kctl)
 {
        int err;
+       unsigned short flags = 0;
        struct hda_nid_item *item;
 
-       if (kctl->id.subdevice & HDA_SUBDEV_NID_FLAG) {
+       if (kctl->id.subdevice & HDA_SUBDEV_AMP_FLAG) {
+               flags |= HDA_NID_ITEM_AMP;
                if (nid == 0)
-                       nid = kctl->id.subdevice & 0xffff;
-               kctl->id.subdevice = 0;
+                       nid = get_amp_nid_(kctl->private_value);
        }
+       if ((kctl->id.subdevice & HDA_SUBDEV_NID_FLAG) != 0 && nid == 0)
+               nid = kctl->id.subdevice & 0xffff;
+       if (kctl->id.subdevice & (HDA_SUBDEV_NID_FLAG|HDA_SUBDEV_AMP_FLAG))
+               kctl->id.subdevice = 0;
        err = snd_ctl_add(codec->bus->card, kctl);
        if (err < 0)
                return err;
@@ -1744,10 +1774,40 @@ int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
                return -ENOMEM;
        item->kctl = kctl;
        item->nid = nid;
+       item->flags = flags;
        return 0;
 }
 EXPORT_SYMBOL_HDA(snd_hda_ctl_add);
 
+/**
+ * snd_hda_add_nid - Assign a NID to a control element
+ * @codec: HD-audio codec
+ * @nid: corresponding NID (optional)
+ * @kctl: the control element to assign
+ * @index: index to kctl
+ *
+ * Add the given control element to an array inside the codec instance.
+ * This function is used when #snd_hda_ctl_add cannot be used for 1:1
+ * NID:KCTL mapping - for example "Capture Source" selector.
+ */
+int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl,
+                   unsigned int index, hda_nid_t nid)
+{
+       struct hda_nid_item *item;
+
+       if (nid > 0) {
+               item = snd_array_new(&codec->nids);
+               if (!item)
+                       return -ENOMEM;
+               item->kctl = kctl;
+               item->index = index;
+               item->nid = nid;
+               return 0;
+       }
+       return -EINVAL;
+}
+EXPORT_SYMBOL_HDA(snd_hda_add_nid);
+
 /**
  * snd_hda_ctls_clear - Clear all controls assigned to the given codec
  * @codec: HD-audio codec
@@ -1759,6 +1819,7 @@ void snd_hda_ctls_clear(struct hda_codec *codec)
        for (i = 0; i < codec->mixers.used; i++)
                snd_ctl_remove(codec->bus->card, items[i].kctl);
        snd_array_free(&codec->mixers);
+       snd_array_free(&codec->nids);
 }
 
 /* pseudo device locking
@@ -2706,7 +2767,8 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
        snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
                            power_state);
        /* partial workaround for "azx_get_response timeout" */
-       if (power_state == AC_PWRST_D0)
+       if (power_state == AC_PWRST_D0 &&
+           (codec->vendor_id & 0xffff0000) == 0x14f10000)
                msleep(10);
 
        nid = codec->start_nid;
@@ -2740,7 +2802,6 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
        if (power_state == AC_PWRST_D0) {
                unsigned long end_time;
                int state;
-               msleep(10);
                /* wait until the codec reachs to D0 */
                end_time = jiffies + msecs_to_jiffies(500);
                do {
@@ -3214,6 +3275,8 @@ const char *snd_hda_pcm_type_name[HDA_PCM_NTYPES] = {
 
 /*
  * get the empty PCM device number to assign
+ *
+ * note the max device number is limited by HDA_MAX_PCMS, currently 10
  */
 static int get_empty_pcm_device(struct hda_bus *bus, int type)
 {
@@ -3478,6 +3541,8 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
 
        for (; knew->name; knew++) {
                struct snd_kcontrol *kctl;
+               if (knew->iface == -1)  /* skip this codec private value */
+                       continue;
                kctl = snd_ctl_new1(knew, codec);
                if (!kctl)
                        return -ENOMEM;
index 0a770a28e71f8b66a6c225bf08133dcec5d99390..b75da47571e6e74bef852d2daba390c6747d0b94 100644 (file)
@@ -527,6 +527,9 @@ enum {
 /* max. codec address */
 #define HDA_MAX_CODEC_ADDRESS  0x0f
 
+/* max number of PCM devics per card */
+#define HDA_MAX_PCMS           10
+
 /*
  * generic arrays
  */
@@ -789,6 +792,7 @@ struct hda_codec {
        u32 *wcaps;
 
        struct snd_array mixers;        /* list of assigned mixer elements */
+       struct snd_array nids;          /* list of mapped mixer elements */
 
        struct hda_cache_rec amp_cache; /* cache for amp access */
        struct hda_cache_rec cmd_cache; /* cache for other commands */
@@ -898,6 +902,7 @@ int snd_hda_codec_set_pincfg(struct hda_codec *codec, hda_nid_t nid,
                             unsigned int cfg);
 int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list,
                       hda_nid_t nid, unsigned int cfg); /* for hwdep */
+void snd_hda_shutup_pins(struct hda_codec *codec);
 
 /*
  * Mixer
index 092c6a7c2ff3f75a23e7dace87351849d03b7c3e..5ea21285ee1f6e700fa320b3710495e47f06aca7 100644 (file)
@@ -861,7 +861,8 @@ static int build_input_controls(struct hda_codec *codec)
        }
 
        /* create input MUX if multiple sources are available */
-       err = snd_hda_ctl_add(codec, 0, snd_ctl_new1(&cap_sel, codec));
+       err = snd_hda_ctl_add(codec, spec->adc_node->nid,
+                             snd_ctl_new1(&cap_sel, codec));
        if (err < 0)
                return err;
 
index 40ccb419b6e97a83bdd253a05c529ad8adfec9d2..a1fc83753cc6951365ac6121cc8fbce0b5287bb2 100644 (file)
@@ -293,8 +293,11 @@ static ssize_t type##_store(struct device *dev,                    \
 {                                                              \
        struct snd_hwdep *hwdep = dev_get_drvdata(dev);         \
        struct hda_codec *codec = hwdep->private_data;          \
-       char *after;                                            \
-       codec->type = simple_strtoul(buf, &after, 0);           \
+       unsigned long val;                                      \
+       int err = strict_strtoul(buf, 0, &val);                 \
+       if (err < 0)                                            \
+               return err;                                     \
+       codec->type = val;                                      \
        return count;                                           \
 }
 
@@ -622,6 +625,10 @@ enum {
        LINE_MODE_PINCFG,
        LINE_MODE_VERB,
        LINE_MODE_HINT,
+       LINE_MODE_VENDOR_ID,
+       LINE_MODE_SUBSYSTEM_ID,
+       LINE_MODE_REVISION_ID,
+       LINE_MODE_CHIP_NAME,
        NUM_LINE_MODES,
 };
 
@@ -651,53 +658,71 @@ static void parse_codec_mode(char *buf, struct hda_bus *bus,
 }
 
 /* parse the contents after the other command tags, [pincfg], [verb],
- * [hint] and [model]
+ * [vendor_id], [subsystem_id], [revision_id], [chip_name], [hint] and [model]
  * just pass to the sysfs helper (only when any codec was specified)
  */
 static void parse_pincfg_mode(char *buf, struct hda_bus *bus,
                              struct hda_codec **codecp)
 {
-       if (!*codecp)
-               return;
        parse_user_pin_configs(*codecp, buf);
 }
 
 static void parse_verb_mode(char *buf, struct hda_bus *bus,
                            struct hda_codec **codecp)
 {
-       if (!*codecp)
-               return;
        parse_init_verbs(*codecp, buf);
 }
 
 static void parse_hint_mode(char *buf, struct hda_bus *bus,
                            struct hda_codec **codecp)
 {
-       if (!*codecp)
-               return;
        parse_hints(*codecp, buf);
 }
 
 static void parse_model_mode(char *buf, struct hda_bus *bus,
                             struct hda_codec **codecp)
 {
-       if (!*codecp)
-               return;
        kfree((*codecp)->modelname);
        (*codecp)->modelname = kstrdup(buf, GFP_KERNEL);
 }
 
+static void parse_chip_name_mode(char *buf, struct hda_bus *bus,
+                                struct hda_codec **codecp)
+{
+       kfree((*codecp)->chip_name);
+       (*codecp)->chip_name = kstrdup(buf, GFP_KERNEL);
+}
+
+#define DEFINE_PARSE_ID_MODE(name) \
+static void parse_##name##_mode(char *buf, struct hda_bus *bus, \
+                                struct hda_codec **codecp) \
+{ \
+       unsigned long val; \
+       if (!strict_strtoul(buf, 0, &val)) \
+               (*codecp)->name = val; \
+}
+
+DEFINE_PARSE_ID_MODE(vendor_id);
+DEFINE_PARSE_ID_MODE(subsystem_id);
+DEFINE_PARSE_ID_MODE(revision_id);
+
+
 struct hda_patch_item {
        const char *tag;
        void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc);
+       int need_codec;
 };
 
 static struct hda_patch_item patch_items[NUM_LINE_MODES] = {
-       [LINE_MODE_CODEC] = { "[codec]", parse_codec_mode },
-       [LINE_MODE_MODEL] = { "[model]", parse_model_mode },
-       [LINE_MODE_VERB] = { "[verb]", parse_verb_mode },
-       [LINE_MODE_PINCFG] = { "[pincfg]", parse_pincfg_mode },
-       [LINE_MODE_HINT] = { "[hint]", parse_hint_mode },
+       [LINE_MODE_CODEC] = { "[codec]", parse_codec_mode, 0 },
+       [LINE_MODE_MODEL] = { "[model]", parse_model_mode, 1 },
+       [LINE_MODE_VERB] = { "[verb]", parse_verb_mode, 1 },
+       [LINE_MODE_PINCFG] = { "[pincfg]", parse_pincfg_mode, 1 },
+       [LINE_MODE_HINT] = { "[hint]", parse_hint_mode, 1 },
+       [LINE_MODE_VENDOR_ID] = { "[vendor_id]", parse_vendor_id_mode, 1 },
+       [LINE_MODE_SUBSYSTEM_ID] = { "[subsystem_id]", parse_subsystem_id_mode, 1 },
+       [LINE_MODE_REVISION_ID] = { "[revision_id]", parse_revision_id_mode, 1 },
+       [LINE_MODE_CHIP_NAME] = { "[chip_name]", parse_chip_name_mode, 1 },
 };
 
 /* check the line starting with '[' -- change the parser mode accodingly */
@@ -780,7 +805,8 @@ int snd_hda_load_patch(struct hda_bus *bus, const char *patch)
                        continue;
                if (*buf == '[')
                        line_mode = parse_line_mode(buf, bus);
-               else if (patch_items[line_mode].parser)
+               else if (patch_items[line_mode].parser &&
+                        (codec || !patch_items[line_mode].need_codec))
                        patch_items[line_mode].parser(buf, bus, &codec);
        }
        release_firmware(fw);
index ff6da6f386d14c7ecdd0975723552680d5080b46..d5c93ad852ee63f7883ccdba924ea41de0e6cc39 100644 (file)
@@ -125,6 +125,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
                         "{Intel, ICH9},"
                         "{Intel, ICH10},"
                         "{Intel, PCH},"
+                        "{Intel, CPT},"
                         "{Intel, SCH},"
                         "{ATI, SB450},"
                         "{ATI, SB600},"
@@ -259,8 +260,6 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
 #define AZX_MAX_FRAG           32
 /* max buffer size - no h/w limit, you can increase as you like */
 #define AZX_MAX_BUF_SIZE       (1024*1024*1024)
-/* max number of PCM devics per card */
-#define AZX_MAX_PCMS           8
 
 /* RIRB int mask: overrun[2], response[0] */
 #define RIRB_INT_RESPONSE      0x01
@@ -408,7 +407,7 @@ struct azx {
        struct azx_dev *azx_dev;
 
        /* PCM */
-       struct snd_pcm *pcm[AZX_MAX_PCMS];
+       struct snd_pcm *pcm[HDA_MAX_PCMS];
 
        /* HD codec */
        unsigned short codec_mask;
@@ -449,6 +448,7 @@ struct azx {
 /* driver types */
 enum {
        AZX_DRIVER_ICH,
+       AZX_DRIVER_PCH,
        AZX_DRIVER_SCH,
        AZX_DRIVER_ATI,
        AZX_DRIVER_ATIHDMI,
@@ -463,6 +463,7 @@ enum {
 
 static char *driver_short_names[] __devinitdata = {
        [AZX_DRIVER_ICH] = "HDA Intel",
+       [AZX_DRIVER_PCH] = "HDA Intel PCH",
        [AZX_DRIVER_SCH] = "HDA Intel MID",
        [AZX_DRIVER_ATI] = "HDA ATI SB",
        [AZX_DRIVER_ATIHDMI] = "HDA ATI HDMI",
@@ -968,8 +969,8 @@ static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev)
        azx_dev->insufficient = 1;
 
        /* enable SIE */
-       azx_writeb(chip, INTCTL,
-                  azx_readb(chip, INTCTL) | (1 << azx_dev->index));
+       azx_writel(chip, INTCTL,
+                  azx_readl(chip, INTCTL) | (1 << azx_dev->index));
        /* set DMA start and interrupt mask */
        azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) |
                      SD_CTL_DMA_START | SD_INT_MASK);
@@ -988,8 +989,8 @@ static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev)
 {
        azx_stream_clear(chip, azx_dev);
        /* disable SIE */
-       azx_writeb(chip, INTCTL,
-                  azx_readb(chip, INTCTL) & ~(1 << azx_dev->index));
+       azx_writel(chip, INTCTL,
+                  azx_readl(chip, INTCTL) & ~(1 << azx_dev->index));
 }
 
 
@@ -1065,6 +1066,7 @@ static void azx_init_pci(struct azx *chip)
                                0x01, NVIDIA_HDA_ENABLE_COHBIT);
                break;
        case AZX_DRIVER_SCH:
+       case AZX_DRIVER_PCH:
                pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop);
                if (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) {
                        pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC,
@@ -1350,7 +1352,7 @@ static void azx_bus_reset(struct hda_bus *bus)
        if (chip->initialized) {
                int i;
 
-               for (i = 0; i < AZX_MAX_PCMS; i++)
+               for (i = 0; i < HDA_MAX_PCMS; i++)
                        snd_pcm_suspend_all(chip->pcm[i]);
                snd_hda_suspend(chip->bus);
                snd_hda_resume(chip->bus);
@@ -1412,7 +1414,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model)
                                chip->codec_mask &= ~(1 << c);
                                /* More badly, accessing to a non-existing
                                 * codec often screws up the controller chip,
-                                * and distrubs the further communications.
+                                * and disturbs the further communications.
                                 * Thus if an error occurs during probing,
                                 * better to reset the controller chip to
                                 * get back to the sanity state.
@@ -1983,7 +1985,7 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
        int pcm_dev = cpcm->device;
        int s, err;
 
-       if (pcm_dev >= AZX_MAX_PCMS) {
+       if (pcm_dev >= HDA_MAX_PCMS) {
                snd_printk(KERN_ERR SFX "Invalid PCM device number %d\n",
                           pcm_dev);
                return -EINVAL;
@@ -2139,7 +2141,7 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state)
 
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
        azx_clear_irq_pending(chip);
-       for (i = 0; i < AZX_MAX_PCMS; i++)
+       for (i = 0; i < HDA_MAX_PCMS; i++)
                snd_pcm_suspend_all(chip->pcm[i]);
        if (chip->initialized)
                snd_hda_suspend(chip->bus);
@@ -2262,6 +2264,7 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = {
        SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB),
+       SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB),
        {}
@@ -2418,6 +2421,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
        if (bdl_pos_adj[dev] < 0) {
                switch (chip->driver_type) {
                case AZX_DRIVER_ICH:
+               case AZX_DRIVER_PCH:
                        bdl_pos_adj[dev] = 1;
                        break;
                default:
@@ -2683,7 +2687,7 @@ static void __devexit azx_remove(struct pci_dev *pci)
 }
 
 /* PCI IDs */
-static struct pci_device_id azx_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 },
@@ -2696,6 +2700,8 @@ static struct pci_device_id azx_ids[] = {
        { PCI_DEVICE(0x8086, 0x3a6e), .driver_data = AZX_DRIVER_ICH },
        /* PCH */
        { PCI_DEVICE(0x8086, 0x3b56), .driver_data = AZX_DRIVER_ICH },
+       /* CPT */
+       { PCI_DEVICE(0x8086, 0x1c20), .driver_data = AZX_DRIVER_PCH },
        /* SCH */
        { PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH },
        /* ATI SB 450/600 */
@@ -2723,32 +2729,10 @@ static struct pci_device_id azx_ids[] = {
        /* ULI M5461 */
        { PCI_DEVICE(0x10b9, 0x5461), .driver_data = AZX_DRIVER_ULI },
        /* NVIDIA MCP */
-       { PCI_DEVICE(0x10de, 0x026c), .driver_data = AZX_DRIVER_NVIDIA },
-       { PCI_DEVICE(0x10de, 0x0371), .driver_data = AZX_DRIVER_NVIDIA },
-       { PCI_DEVICE(0x10de, 0x03e4), .driver_data = AZX_DRIVER_NVIDIA },
-       { PCI_DEVICE(0x10de, 0x03f0), .driver_data = AZX_DRIVER_NVIDIA },
-       { PCI_DEVICE(0x10de, 0x044a), .driver_data = AZX_DRIVER_NVIDIA },
-       { PCI_DEVICE(0x10de, 0x044b), .driver_data = AZX_DRIVER_NVIDIA },
-       { PCI_DEVICE(0x10de, 0x055c), .driver_data = AZX_DRIVER_NVIDIA },
-       { PCI_DEVICE(0x10de, 0x055d), .driver_data = AZX_DRIVER_NVIDIA },
-       { PCI_DEVICE(0x10de, 0x0590), .driver_data = AZX_DRIVER_NVIDIA },
-       { PCI_DEVICE(0x10de, 0x0774), .driver_data = AZX_DRIVER_NVIDIA },
-       { PCI_DEVICE(0x10de, 0x0775), .driver_data = AZX_DRIVER_NVIDIA },
-       { PCI_DEVICE(0x10de, 0x0776), .driver_data = AZX_DRIVER_NVIDIA },
-       { PCI_DEVICE(0x10de, 0x0777), .driver_data = AZX_DRIVER_NVIDIA },
-       { PCI_DEVICE(0x10de, 0x07fc), .driver_data = AZX_DRIVER_NVIDIA },
-       { PCI_DEVICE(0x10de, 0x07fd), .driver_data = AZX_DRIVER_NVIDIA },
-       { PCI_DEVICE(0x10de, 0x0ac0), .driver_data = AZX_DRIVER_NVIDIA },
-       { PCI_DEVICE(0x10de, 0x0ac1), .driver_data = AZX_DRIVER_NVIDIA },
-       { PCI_DEVICE(0x10de, 0x0ac2), .driver_data = AZX_DRIVER_NVIDIA },
-       { PCI_DEVICE(0x10de, 0x0ac3), .driver_data = AZX_DRIVER_NVIDIA },
-       { PCI_DEVICE(0x10de, 0x0be2), .driver_data = AZX_DRIVER_NVIDIA },
-       { PCI_DEVICE(0x10de, 0x0be3), .driver_data = AZX_DRIVER_NVIDIA },
-       { PCI_DEVICE(0x10de, 0x0be4), .driver_data = AZX_DRIVER_NVIDIA },
-       { PCI_DEVICE(0x10de, 0x0d94), .driver_data = AZX_DRIVER_NVIDIA },
-       { PCI_DEVICE(0x10de, 0x0d95), .driver_data = AZX_DRIVER_NVIDIA },
-       { PCI_DEVICE(0x10de, 0x0d96), .driver_data = AZX_DRIVER_NVIDIA },
-       { PCI_DEVICE(0x10de, 0x0d97), .driver_data = AZX_DRIVER_NVIDIA },
+       { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID),
+         .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
+         .class_mask = 0xffffff,
+         .driver_data = AZX_DRIVER_NVIDIA },
        /* Teradici */
        { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA },
        /* Creative X-Fi (CA0110-IBG) */
index 5778ae882b839fb918d597f29193aa9f75c054ee..7cee364976ff3e7488cb0443a7c64b853cfbe781 100644 (file)
@@ -31,6 +31,7 @@
  * in snd_hda_ctl_add(), so that this value won't appear in the outside.
  */
 #define HDA_SUBDEV_NID_FLAG    (1U << 31)
+#define HDA_SUBDEV_AMP_FLAG    (1U << 30)
 
 /*
  * for mixer controls
@@ -42,7 +43,7 @@
 /* mono volume with index (index=0,1,...) (channel=1,2) */
 #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
        { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx,  \
-         .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \
+         .subdevice = HDA_SUBDEV_AMP_FLAG, \
          .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
                    SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
                    SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \
@@ -63,7 +64,7 @@
 /* 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, \
-         .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \
+         .subdevice = HDA_SUBDEV_AMP_FLAG, \
          .info = snd_hda_mixer_amp_switch_info, \
          .get = snd_hda_mixer_amp_switch_get, \
          .put = snd_hda_mixer_amp_switch_put, \
@@ -81,7 +82,7 @@
 /* special beep mono mute switch with index (index=0,1,...) (channel=1,2) */
 #define HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
        { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
-         .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \
+         .subdevice = HDA_SUBDEV_AMP_FLAG, \
          .info = snd_hda_mixer_amp_switch_info, \
          .get = snd_hda_mixer_amp_switch_get, \
          .put = snd_hda_mixer_amp_switch_put_beep, \
@@ -464,13 +465,20 @@ u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid);
 u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid);
 int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid);
 
+/* flags for hda_nid_item */
+#define HDA_NID_ITEM_AMP       (1<<0)
+
 struct hda_nid_item {
        struct snd_kcontrol *kctl;
+       unsigned int index;
        hda_nid_t nid;
+       unsigned short flags;
 };
 
 int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
                    struct snd_kcontrol *kctl);
+int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl,
+                   unsigned int index, hda_nid_t nid);
 void snd_hda_ctls_clear(struct hda_codec *codec);
 
 /*
index c9afc04adac8d126c302b7c11bcdc183b355766a..f97d35de66c41b2e9f276ce5fec037aedde27985 100644 (file)
@@ -61,18 +61,29 @@ static const char *get_wid_type_name(unsigned int wid_value)
                return "UNKNOWN Widget";
 }
 
-static void print_nid_mixers(struct snd_info_buffer *buffer,
-                            struct hda_codec *codec, hda_nid_t nid)
+static void print_nid_array(struct snd_info_buffer *buffer,
+                           struct hda_codec *codec, hda_nid_t nid,
+                           struct snd_array *array)
 {
        int i;
-       struct hda_nid_item *items = codec->mixers.list;
+       struct hda_nid_item *items = array->list, *item;
        struct snd_kcontrol *kctl;
-       for (i = 0; i < codec->mixers.used; i++) {
-               if (items[i].nid == nid) {
-                       kctl = items[i].kctl;
+       for (i = 0; i < array->used; i++) {
+               item = &items[i];
+               if (item->nid == nid) {
+                       kctl = item->kctl;
                        snd_iprintf(buffer,
                          "  Control: name=\"%s\", index=%i, device=%i\n",
-                         kctl->id.name, kctl->id.index, kctl->id.device);
+                         kctl->id.name, kctl->id.index + item->index,
+                         kctl->id.device);
+                       if (item->flags & HDA_NID_ITEM_AMP)
+                               snd_iprintf(buffer,
+                                 "    ControlAmp: chs=%lu, dir=%s, "
+                                 "idx=%lu, ofs=%lu\n",
+                                 get_amp_channels(kctl),
+                                 get_amp_direction(kctl) ? "Out" : "In",
+                                 get_amp_index(kctl),
+                                 get_amp_offset(kctl));
                }
        }
 }
@@ -528,7 +539,8 @@ static void print_gpio(struct snd_info_buffer *buffer,
                            (data & (1<<i)) ? 1 : 0,
                            (unsol & (1<<i)) ? 1 : 0);
        /* FIXME: add GPO and GPI pin information */
-       print_nid_mixers(buffer, codec, nid);
+       print_nid_array(buffer, codec, nid, &codec->mixers);
+       print_nid_array(buffer, codec, nid, &codec->nids);
 }
 
 static void print_codec_info(struct snd_info_entry *entry,
@@ -608,7 +620,8 @@ static void print_codec_info(struct snd_info_entry *entry,
                        snd_iprintf(buffer, " CP");
                snd_iprintf(buffer, "\n");
 
-               print_nid_mixers(buffer, codec, nid);
+               print_nid_array(buffer, codec, nid, &codec->mixers);
+               print_nid_array(buffer, codec, nid, &codec->nids);
                print_nid_pcms(buffer, codec, nid);
 
                /* volume knob is a special widget that always have connection
index 69a941c7b1588b7db4a9acd0fe79da65824c8944..e6d1bdff1b6e56f53778ace479d682eaf385d915 100644 (file)
@@ -174,6 +174,7 @@ static struct snd_kcontrol_new ad_beep_mixer[] = {
 static int ad198x_build_controls(struct hda_codec *codec)
 {
        struct ad198x_spec *spec = codec->spec;
+       struct snd_kcontrol *kctl;
        unsigned int i;
        int err;
 
@@ -208,9 +209,7 @@ static int ad198x_build_controls(struct hda_codec *codec)
                        if (!kctl)
                                return -ENOMEM;
                        kctl->private_value = spec->beep_amp;
-                       err = snd_hda_ctl_add(codec,
-                                               get_amp_nid_(spec->beep_amp),
-                                               kctl);
+                       err = snd_hda_ctl_add(codec, 0, kctl);
                        if (err < 0)
                                return err;
                }
@@ -239,6 +238,27 @@ static int ad198x_build_controls(struct hda_codec *codec)
        }
 
        ad198x_free_kctls(codec); /* no longer needed */
+
+       /* assign Capture Source enums to NID */
+       kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
+       if (!kctl)
+               kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
+       for (i = 0; kctl && i < kctl->count; i++) {
+               err = snd_hda_add_nid(codec, kctl, i, spec->capsrc_nids[i]);
+               if (err < 0)
+                       return err;
+       }
+
+       /* assign IEC958 enums to NID */
+       kctl = snd_hda_find_mixer_ctl(codec,
+                       SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source");
+       if (kctl) {
+               err = snd_hda_add_nid(codec, kctl, 0,
+                                     spec->multiout.dig_out_nid);
+               if (err < 0)
+                       return err;
+       }
+
        return 0;
 }
 
@@ -421,6 +441,11 @@ static int ad198x_build_pcms(struct hda_codec *codec)
        return 0;
 }
 
+static inline void ad198x_shutup(struct hda_codec *codec)
+{
+       snd_hda_shutup_pins(codec);
+}
+
 static void ad198x_free_kctls(struct hda_codec *codec)
 {
        struct ad198x_spec *spec = codec->spec;
@@ -434,6 +459,46 @@ static void ad198x_free_kctls(struct hda_codec *codec)
        snd_array_free(&spec->kctls);
 }
 
+static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front,
+                               hda_nid_t hp)
+{
+       struct ad198x_spec *spec = codec->spec;
+       snd_hda_codec_write(codec, front, 0, AC_VERB_SET_EAPD_BTLENABLE,
+                           !spec->inv_eapd ? 0x00 : 0x02);
+       snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_EAPD_BTLENABLE,
+                           !spec->inv_eapd ? 0x00 : 0x02);
+}
+
+static void ad198x_power_eapd(struct hda_codec *codec)
+{
+       /* We currently only handle front, HP */
+       switch (codec->vendor_id) {
+       case 0x11d41882:
+       case 0x11d4882a:
+       case 0x11d41884:
+       case 0x11d41984:
+       case 0x11d41883:
+       case 0x11d4184a:
+       case 0x11d4194a:
+       case 0x11d4194b:
+               ad198x_power_eapd_write(codec, 0x12, 0x11);
+               break;
+       case 0x11d41981:
+       case 0x11d41983:
+               ad198x_power_eapd_write(codec, 0x05, 0x06);
+               break;
+       case 0x11d41986:
+               ad198x_power_eapd_write(codec, 0x1b, 0x1a);
+               break;
+       case 0x11d41988:
+       case 0x11d4198b:
+       case 0x11d4989a:
+       case 0x11d4989b:
+               ad198x_power_eapd_write(codec, 0x29, 0x22);
+               break;
+       }
+}
+
 static void ad198x_free(struct hda_codec *codec)
 {
        struct ad198x_spec *spec = codec->spec;
@@ -441,11 +506,29 @@ static void ad198x_free(struct hda_codec *codec)
        if (!spec)
                return;
 
+       ad198x_shutup(codec);
        ad198x_free_kctls(codec);
        kfree(spec);
        snd_hda_detach_beep_device(codec);
 }
 
+#ifdef SND_HDA_NEEDS_RESUME
+static int ad198x_suspend(struct hda_codec *codec, pm_message_t state)
+{
+       ad198x_shutup(codec);
+       ad198x_power_eapd(codec);
+       return 0;
+}
+
+static int ad198x_resume(struct hda_codec *codec)
+{
+       ad198x_init(codec);
+       snd_hda_codec_resume_amp(codec);
+       snd_hda_codec_resume_cache(codec);
+       return 0;
+}
+#endif
+
 static struct hda_codec_ops ad198x_patch_ops = {
        .build_controls = ad198x_build_controls,
        .build_pcms = ad198x_build_pcms,
@@ -454,6 +537,11 @@ static struct hda_codec_ops ad198x_patch_ops = {
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        .check_power_status = ad198x_check_power_status,
 #endif
+#ifdef SND_HDA_NEEDS_RESUME
+       .suspend = ad198x_suspend,
+       .resume = ad198x_resume,
+#endif
+       .reboot_notify = ad198x_shutup,
 };
 
 
@@ -701,6 +789,7 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "External Amplifier",
+               .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
                .info = ad198x_eapd_info,
                .get = ad198x_eapd_get,
                .put = ad198x_eapd_put,
@@ -808,6 +897,7 @@ static struct snd_kcontrol_new ad1986a_automute_master_mixers[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Master Playback Switch",
+               .subdevice = HDA_SUBDEV_AMP_FLAG,
                .info = snd_hda_mixer_amp_switch_info,
                .get = snd_hda_mixer_amp_switch_get,
                .put = ad1986a_hp_master_sw_put,
@@ -1008,7 +1098,7 @@ static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK),
        SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK),
        SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK),
-       SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba", AD1986A_LAPTOP_EAPD),
+       SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40-10Q", AD1986A_3STACK),
        SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK),
        SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
        SND_PCI_QUIRK(0x144d, 0xc024, "Samsung P50", AD1986A_SAMSUNG_P50),
@@ -1612,6 +1702,7 @@ static struct snd_kcontrol_new ad1981_hp_mixers[] = {
        HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol),
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .subdevice = HDA_SUBDEV_NID_FLAG | 0x05,
                .name = "Master Playback Switch",
                .info = ad198x_eapd_info,
                .get = ad198x_eapd_get,
@@ -2136,6 +2227,7 @@ static struct snd_kcontrol_new ad1988_laptop_mixers[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "External Amplifier",
+               .subdevice = HDA_SUBDEV_NID_FLAG | 0x12,
                .info = ad198x_eapd_info,
                .get = ad198x_eapd_get,
                .put = ad198x_eapd_put,
@@ -2257,6 +2349,7 @@ static struct snd_kcontrol_new ad1988_spdif_out_mixers[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "IEC958 Playback Source",
+               .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
                .info = ad1988_spdif_playback_source_info,
                .get = ad1988_spdif_playback_source_get,
                .put = ad1988_spdif_playback_source_put,
@@ -2372,6 +2465,12 @@ static struct hda_verb ad1988_spdif_init_verbs[] = {
        { }
 };
 
+static struct hda_verb ad1988_spdif_in_init_verbs[] = {
+       /* unmute SPDIF input pin */
+       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       { }
+};
+
 /* AD1989 has no ADC -> SPDIF route */
 static struct hda_verb ad1989_spdif_init_verbs[] = {
        /* SPDIF-1 out pin */
@@ -2589,7 +2688,7 @@ static int add_control(struct ad198x_spec *spec, int type, const char *name,
        if (! knew->name)
                return -ENOMEM;
        if (get_amp_nid_(val))
-               knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val);
+               knew->subdevice = HDA_SUBDEV_AMP_FLAG;
        knew->private_value = val;
        return 0;
 }
@@ -3107,8 +3206,11 @@ static int patch_ad1988(struct hda_codec *codec)
                                ad1988_spdif_init_verbs;
                }
        }
-       if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a)
+       if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a) {
                spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers;
+               spec->init_verbs[spec->num_init_verbs++] =
+                       ad1988_spdif_in_init_verbs;
+       }
 
        codec->patch_ops = ad198x_patch_ops;
        switch (board_config) {
@@ -3747,6 +3849,7 @@ static struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Master Playback Switch",
+               .subdevice = HDA_SUBDEV_AMP_FLAG,
                .info = snd_hda_mixer_amp_switch_info,
                .get = snd_hda_mixer_amp_switch_get,
                .put = ad1884a_mobile_master_sw_put,
@@ -3775,6 +3878,7 @@ static struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Master Playback Switch",
+               .subdevice = HDA_SUBDEV_AMP_FLAG,
                .info = snd_hda_mixer_amp_switch_info,
                .get = snd_hda_mixer_amp_switch_get,
                .put = ad1884a_mobile_master_sw_put,
@@ -4116,6 +4220,7 @@ static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = {
 /*     HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .subdevice = HDA_SUBDEV_AMP_FLAG,
                .name = "Master Playback Switch",
                .info = snd_hda_mixer_amp_switch_info,
                .get = snd_hda_mixer_amp_switch_get,
index fe0423c39598b9a98fca8f1f7af48c5bb9c7eaa9..7de782a5b8f4ccb784707e4027f111c12538b27b 100644 (file)
@@ -501,7 +501,8 @@ static int add_mute(struct hda_codec *codec, const char *name, int index,
        knew.private_value = pval;
        snprintf(tmp, sizeof(tmp), "%s %s Switch", name, dir_sfx[dir]);
        *kctlp = snd_ctl_new1(&knew, codec);
-       return snd_hda_ctl_add(codec, get_amp_nid_(pval), *kctlp);
+       (*kctlp)->id.subdevice = HDA_SUBDEV_AMP_FLAG;
+       return snd_hda_ctl_add(codec, 0, *kctlp);
 }
 
 static int add_volume(struct hda_codec *codec, const char *name,
@@ -514,7 +515,8 @@ static int add_volume(struct hda_codec *codec, const char *name,
        knew.private_value = pval;
        snprintf(tmp, sizeof(tmp), "%s %s Volume", name, dir_sfx[dir]);
        *kctlp = snd_ctl_new1(&knew, codec);
-       return snd_hda_ctl_add(codec, get_amp_nid_(pval), *kctlp);
+       (*kctlp)->id.subdevice = HDA_SUBDEV_AMP_FLAG;
+       return snd_hda_ctl_add(codec, 0, *kctlp);
 }
 
 static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac)
@@ -751,6 +753,7 @@ static int build_input(struct hda_codec *codec)
        spec->capture_bind[1] = make_bind_capture(codec, &snd_hda_bind_vol);
        for (i = 0; i < 2; i++) {
                struct snd_kcontrol *kctl;
+               int n;
                if (!spec->capture_bind[i])
                        return -ENOMEM;
                kctl = snd_ctl_new1(&cs_capture_ctls[i], codec);
@@ -760,6 +763,13 @@ static int build_input(struct hda_codec *codec)
                err = snd_hda_ctl_add(codec, 0, kctl);
                if (err < 0)
                        return err;
+               for (n = 0; n < AUTO_PIN_LAST; n++) {
+                       if (!spec->adc_nid[n])
+                               continue;
+                       err = snd_hda_add_nid(codec, kctl, 0, spec->adc_nid[i]);
+                       if (err < 0)
+                               return err;
+               }
        }
        
        if (spec->num_inputs > 1 && !spec->mic_detect) {
index a45c1169762b5a6ffa021947ee2feab26b9530e2..ff60908f4554ad1b15bbbae2973929e25a9458ef 100644 (file)
@@ -315,7 +315,8 @@ static struct hda_verb cmi9880_allout_init[] = {
 static int cmi9880_build_controls(struct hda_codec *codec)
 {
        struct cmi_spec *spec = codec->spec;
-       int err;
+       struct snd_kcontrol *kctl;
+       int i, err;
 
        err = snd_hda_add_new_ctls(codec, cmi9880_basic_mixer);
        if (err < 0)
@@ -340,6 +341,14 @@ static int cmi9880_build_controls(struct hda_codec *codec)
                if (err < 0)
                        return err;
        }
+
+       /* assign Capture Source enums to NID */
+       kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
+       for (i = 0; kctl && i < kctl->count; i++) {
+               err = snd_hda_add_nid(codec, kctl, i, spec->adc_nids[i]);
+               if (err < 0)
+                       return err;
+       }
        return 0;
 }
 
index c578c28f368eba10cc6baacb4ea81e549436af14..194a28c5499219b99d3b10ed2ae357cde7707679 100644 (file)
 
 /* Conexant 5051 specific */
 
-#define CXT5051_SPDIF_OUT      0x1C
+#define CXT5051_SPDIF_OUT      0x12
 #define CXT5051_PORTB_EVENT    0x38
 #define CXT5051_PORTC_EVENT    0x39
 
+#define AUTO_MIC_PORTB         (1 << 1)
+#define AUTO_MIC_PORTC         (1 << 2)
 
 struct conexant_jack {
 
@@ -74,7 +76,7 @@ struct conexant_spec {
                                         */
        unsigned int cur_eapd;
        unsigned int hp_present;
-       unsigned int no_auto_mic;
+       unsigned int auto_mic;
        unsigned int need_dac_fix;
 
        /* capture */
@@ -111,8 +113,23 @@ struct conexant_spec {
 
        unsigned int dell_automute;
        unsigned int port_d_mode;
-       unsigned char ext_mic_bias;
-       unsigned int dell_vostro;
+       unsigned int dell_vostro:1;
+       unsigned int ideapad:1;
+
+       unsigned int ext_mic_present;
+       unsigned int recording;
+       void (*capture_prepare)(struct hda_codec *codec);
+       void (*capture_cleanup)(struct hda_codec *codec);
+
+       /* OLPC XO-1.5 supports DC input mode (e.g. for use with analog sensors)
+        * through the microphone jack.
+        * When the user enables this through a mixer switch, both internal and
+        * external microphones are disabled. Gain is fixed at 0dB. In this mode,
+        * we also allow the bias to be configured through a separate mixer
+        * control. */
+       unsigned int dc_enable;
+       unsigned int dc_input_bias; /* offset into cxt5066_olpc_dc_bias */
+       unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */
 };
 
 static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo,
@@ -185,6 +202,8 @@ static int conexant_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
                                      struct snd_pcm_substream *substream)
 {
        struct conexant_spec *spec = codec->spec;
+       if (spec->capture_prepare)
+               spec->capture_prepare(codec);
        snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
                                   stream_tag, 0, format);
        return 0;
@@ -196,6 +215,8 @@ static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
 {
        struct conexant_spec *spec = codec->spec;
        snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
+       if (spec->capture_cleanup)
+               spec->capture_cleanup(codec);
        return 0;
 }
 
@@ -1585,6 +1606,11 @@ static void cxt5051_update_speaker(struct hda_codec *codec)
 {
        struct conexant_spec *spec = codec->spec;
        unsigned int pinctl;
+       /* headphone pin */
+       pinctl = (spec->hp_present && spec->cur_eapd) ? PIN_HP : 0;
+       snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+                           pinctl);
+       /* speaker pin */
        pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0;
        snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
                            pinctl);
@@ -1608,7 +1634,7 @@ static void cxt5051_portb_automic(struct hda_codec *codec)
        struct conexant_spec *spec = codec->spec;
        unsigned int present;
 
-       if (spec->no_auto_mic)
+       if (!(spec->auto_mic & AUTO_MIC_PORTB))
                return;
        present = snd_hda_jack_detect(codec, 0x17);
        snd_hda_codec_write(codec, 0x14, 0,
@@ -1623,7 +1649,7 @@ static void cxt5051_portc_automic(struct hda_codec *codec)
        unsigned int present;
        hda_nid_t new_adc;
 
-       if (spec->no_auto_mic)
+       if (!(spec->auto_mic & AUTO_MIC_PORTC))
                return;
        present = snd_hda_jack_detect(codec, 0x18);
        if (present)
@@ -1669,13 +1695,7 @@ static void cxt5051_hp_unsol_event(struct hda_codec *codec,
        conexant_report_jack(codec, nid);
 }
 
-static struct snd_kcontrol_new cxt5051_mixers[] = {
-       HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Docking Mic Volume", 0x15, 0x00, HDA_INPUT),
-       HDA_CODEC_MUTE("Docking Mic Switch", 0x15, 0x00, HDA_INPUT),
+static struct snd_kcontrol_new cxt5051_playback_mixers[] = {
        HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT),
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -1685,7 +1705,16 @@ static struct snd_kcontrol_new cxt5051_mixers[] = {
                .put = cxt5051_hp_master_sw_put,
                .private_value = 0x1a,
        },
+       {}
+};
 
+static struct snd_kcontrol_new cxt5051_capture_mixers[] = {
+       HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Docking Mic Volume", 0x15, 0x00, HDA_INPUT),
+       HDA_CODEC_MUTE("Docking Mic Switch", 0x15, 0x00, HDA_INPUT),
        {}
 };
 
@@ -1694,32 +1723,26 @@ static struct snd_kcontrol_new cxt5051_hp_mixers[] = {
        HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
        HDA_CODEC_VOLUME("External Mic Volume", 0x15, 0x00, HDA_INPUT),
        HDA_CODEC_MUTE("External Mic Switch", 0x15, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Master Playback Switch",
-               .info = cxt_eapd_info,
-               .get = cxt_eapd_get,
-               .put = cxt5051_hp_master_sw_put,
-               .private_value = 0x1a,
-       },
-
        {}
 };
 
 static struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = {
-       HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x00, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Switch", 0x14, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Master Playback Switch",
-               .info = cxt_eapd_info,
-               .get = cxt_eapd_get,
-               .put = cxt5051_hp_master_sw_put,
-               .private_value = 0x1a,
-       },
+       HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x00, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x14, 0x00, HDA_INPUT),
+       {}
+};
 
+static struct snd_kcontrol_new cxt5051_f700_mixers[] = {
+       HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x14, 0x01, HDA_INPUT),
+       {}
+};
+
+static struct snd_kcontrol_new cxt5051_toshiba_mixers[] = {
+       HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT),
        {}
 };
 
@@ -1748,8 +1771,6 @@ static struct hda_verb cxt5051_init_verbs[] = {
        /* EAPD */
        {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ 
        {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
-       {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTC_EVENT},
        { } /* end */
 };
 
@@ -1775,7 +1796,6 @@ static struct hda_verb cxt5051_hp_dv6736_init_verbs[] = {
        /* EAPD */
        {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
        {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
-       {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT},
        { } /* end */
 };
 
@@ -1807,17 +1827,60 @@ static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = {
        /* EAPD */
        {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
        {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
-       {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTC_EVENT},
        {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
        { } /* end */
 };
 
+static struct hda_verb cxt5051_f700_init_verbs[] = {
+       /* Line in, Mic */
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0},
+       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0},
+       /* SPK  */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* HP, Amp  */
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* DAC1 */
+       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* Record selector: Int mic */
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x1},
+       /* SPDIF route: PCM */
+       {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0},
+       /* EAPD */
+       {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
+       {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
+       { } /* end */
+};
+
+static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid,
+                                unsigned int event)
+{
+       snd_hda_codec_write(codec, nid, 0,
+                           AC_VERB_SET_UNSOLICITED_ENABLE,
+                           AC_USRSP_EN | event);
+#ifdef CONFIG_SND_HDA_INPUT_JACK
+       conexant_add_jack(codec, nid, SND_JACK_MICROPHONE);
+       conexant_report_jack(codec, nid);
+#endif
+}
+
 /* initialize jack-sensing, too */
 static int cxt5051_init(struct hda_codec *codec)
 {
+       struct conexant_spec *spec = codec->spec;
+
        conexant_init(codec);
        conexant_init_jacks(codec);
+
+       if (spec->auto_mic & AUTO_MIC_PORTB)
+               cxt5051_init_mic_port(codec, 0x17, CXT5051_PORTB_EVENT);
+       if (spec->auto_mic & AUTO_MIC_PORTC)
+               cxt5051_init_mic_port(codec, 0x18, CXT5051_PORTC_EVENT);
+
        if (codec->patch_ops.unsol_event) {
                cxt5051_hp_automute(codec);
                cxt5051_portb_automic(codec);
@@ -1832,6 +1895,8 @@ enum {
        CXT5051_HP,     /* no docking */
        CXT5051_HP_DV6736,      /* HP without mic switch */
        CXT5051_LENOVO_X200,    /* Lenovo X200 laptop */
+       CXT5051_F700,       /* HP Compaq Presario F700 */
+       CXT5051_TOSHIBA,        /* Toshiba M300 & co */
        CXT5051_MODELS
 };
 
@@ -1840,11 +1905,15 @@ static const char *cxt5051_models[CXT5051_MODELS] = {
        [CXT5051_HP]            = "hp",
        [CXT5051_HP_DV6736]     = "hp-dv6736",
        [CXT5051_LENOVO_X200]   = "lenovo-x200",
+       [CXT5051_F700]          = "hp-700",
+       [CXT5051_TOSHIBA]       = "toshiba",
 };
 
 static struct snd_pci_quirk cxt5051_cfg_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6736", CXT5051_HP_DV6736),
        SND_PCI_QUIRK(0x103c, 0x360b, "Compaq Presario CQ60", CXT5051_HP),
+       SND_PCI_QUIRK(0x103c, 0x30ea, "Compaq Presario F700", CXT5051_F700),
+       SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba M30x", CXT5051_TOSHIBA),
        SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board",
                      CXT5051_LAPTOP),
        SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP),
@@ -1872,8 +1941,9 @@ static int patch_cxt5051(struct hda_codec *codec)
        spec->multiout.dig_out_nid = CXT5051_SPDIF_OUT;
        spec->num_adc_nids = 1; /* not 2; via auto-mic switch */
        spec->adc_nids = cxt5051_adc_nids;
-       spec->num_mixers = 1;
-       spec->mixers[0] = cxt5051_mixers;
+       spec->num_mixers = 2;
+       spec->mixers[0] = cxt5051_capture_mixers;
+       spec->mixers[1] = cxt5051_playback_mixers;
        spec->num_init_verbs = 1;
        spec->init_verbs[0] = cxt5051_init_verbs;
        spec->spdif_route = 0;
@@ -1887,6 +1957,7 @@ static int patch_cxt5051(struct hda_codec *codec)
        board_config = snd_hda_check_board_config(codec, CXT5051_MODELS,
                                                  cxt5051_models,
                                                  cxt5051_cfg_tbl);
+       spec->auto_mic = AUTO_MIC_PORTB | AUTO_MIC_PORTC;
        switch (board_config) {
        case CXT5051_HP:
                spec->mixers[0] = cxt5051_hp_mixers;
@@ -1894,11 +1965,20 @@ static int patch_cxt5051(struct hda_codec *codec)
        case CXT5051_HP_DV6736:
                spec->init_verbs[0] = cxt5051_hp_dv6736_init_verbs;
                spec->mixers[0] = cxt5051_hp_dv6736_mixers;
-               spec->no_auto_mic = 1;
+               spec->auto_mic = 0;
                break;
        case CXT5051_LENOVO_X200:
                spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs;
                break;
+       case CXT5051_F700:
+               spec->init_verbs[0] = cxt5051_f700_init_verbs;
+               spec->mixers[0] = cxt5051_f700_mixers;
+               spec->auto_mic = 0;
+               break;
+       case CXT5051_TOSHIBA:
+               spec->mixers[0] = cxt5051_toshiba_mixers;
+               spec->auto_mic = AUTO_MIC_PORTB;
+               break;
        }
 
        return 0;
@@ -1966,33 +2046,117 @@ static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol,
        return 1;
 }
 
+static const struct hda_input_mux cxt5066_olpc_dc_bias = {
+       .num_items = 3,
+       .items = {
+               { "Off", PIN_IN },
+               { "50%", PIN_VREF50 },
+               { "80%", PIN_VREF80 },
+       },
+};
+
+static int cxt5066_set_olpc_dc_bias(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       /* Even though port F is the DC input, the bias is controlled on port B.
+        * we also leave that port as an active input (but unselected) in DC mode
+        * just in case that is necessary to make the bias setting take effect. */
+       return snd_hda_codec_write_cache(codec, 0x1a, 0,
+               AC_VERB_SET_PIN_WIDGET_CONTROL,
+               cxt5066_olpc_dc_bias.items[spec->dc_input_bias].index);
+}
+
+/* OLPC defers mic widget control until when capture is started because the
+ * microphone LED comes on as soon as these settings are put in place. if we
+ * did this before recording, it would give the false indication that recording
+ * is happening when it is not. */
+static void cxt5066_olpc_select_mic(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       if (!spec->recording)
+               return;
+
+       if (spec->dc_enable) {
+               /* in DC mode we ignore presence detection and just use the jack
+                * through our special DC port */
+               const struct hda_verb enable_dc_mode[] = {
+                       /* disble internal mic, port C */
+                       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+
+                       /* enable DC capture, port F */
+                       {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+                       {},
+               };
+
+               snd_hda_sequence_write(codec, enable_dc_mode);
+               /* port B input disabled (and bias set) through the following call */
+               cxt5066_set_olpc_dc_bias(codec);
+               return;
+       }
+
+       /* disable DC (port F) */
+       snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+
+       /* external mic, port B */
+       snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+               spec->ext_mic_present ? CXT5066_OLPC_EXT_MIC_BIAS : 0);
+
+       /* internal mic, port C */
+       snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+               spec->ext_mic_present ? 0 : PIN_VREF80);
+}
+
 /* toggle input of built-in and mic jack appropriately */
-static void cxt5066_automic(struct hda_codec *codec)
+static void cxt5066_olpc_automic(struct hda_codec *codec)
 {
        struct conexant_spec *spec = codec->spec;
+       unsigned int present;
+
+       if (spec->dc_enable) /* don't do presence detection in DC mode */
+               return;
+
+       present = snd_hda_codec_read(codec, 0x1a, 0,
+                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       if (present)
+               snd_printdd("CXT5066: external microphone detected\n");
+       else
+               snd_printdd("CXT5066: external microphone absent\n");
+
+       snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL,
+               present ? 0 : 1);
+       spec->ext_mic_present = !!present;
+
+       cxt5066_olpc_select_mic(codec);
+}
+
+/* toggle input of built-in digital mic and mic jack appropriately */
+static void cxt5066_vostro_automic(struct hda_codec *codec)
+{
+       unsigned int present;
+
        struct hda_verb ext_mic_present[] = {
                /* enable external mic, port B */
-               {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_bias},
+               {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
 
                /* switch to external mic input */
                {0x17, AC_VERB_SET_CONNECT_SEL, 0},
+               {0x14, AC_VERB_SET_CONNECT_SEL, 0},
 
-               /* disable internal mic, port C */
-               {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+               /* disable internal digital mic */
+               {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
                {}
        };
        static struct hda_verb ext_mic_absent[] = {
                /* enable internal mic, port C */
-               {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+               {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 
                /* switch to internal mic input */
-               {0x17, AC_VERB_SET_CONNECT_SEL, 1},
+               {0x14, AC_VERB_SET_CONNECT_SEL, 2},
 
                /* disable external mic, port B */
                {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
                {}
        };
-       unsigned int present;
 
        present = snd_hda_jack_detect(codec, 0x1a);
        if (present) {
@@ -2005,36 +2169,24 @@ static void cxt5066_automic(struct hda_codec *codec)
 }
 
 /* toggle input of built-in digital mic and mic jack appropriately */
-static void cxt5066_vostro_automic(struct hda_codec *codec)
+static void cxt5066_ideapad_automic(struct hda_codec *codec)
 {
-       struct conexant_spec *spec = codec->spec;
        unsigned int present;
 
        struct hda_verb ext_mic_present[] = {
-               /* enable external mic, port B */
-               {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_bias},
-
-               /* switch to external mic input */
-               {0x17, AC_VERB_SET_CONNECT_SEL, 0},
                {0x14, AC_VERB_SET_CONNECT_SEL, 0},
-
-               /* disable internal digital mic */
+               {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
                {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
                {}
        };
        static struct hda_verb ext_mic_absent[] = {
-               /* enable internal mic, port C */
-               {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
-               /* switch to internal mic input */
                {0x14, AC_VERB_SET_CONNECT_SEL, 2},
-
-               /* disable external mic, port B */
-               {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+               {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+               {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
                {}
        };
 
-       present = snd_hda_jack_detect(codec, 0x1a);
+       present = snd_hda_jack_detect(codec, 0x1b);
        if (present) {
                snd_printdd("CXT5066: external microphone detected\n");
                snd_hda_sequence_write(codec, ext_mic_present);
@@ -2063,15 +2215,18 @@ static void cxt5066_hp_automute(struct hda_codec *codec)
 }
 
 /* unsolicited event for jack sensing */
-static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res)
+static void cxt5066_olpc_unsol_event(struct hda_codec *codec, unsigned int res)
 {
+       struct conexant_spec *spec = codec->spec;
        snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26);
        switch (res >> 26) {
        case CONEXANT_HP_EVENT:
                cxt5066_hp_automute(codec);
                break;
        case CONEXANT_MIC_EVENT:
-               cxt5066_automic(codec);
+               /* ignore mic events in DC mode; we're always using the jack */
+               if (!spec->dc_enable)
+                       cxt5066_olpc_automic(codec);
                break;
        }
 }
@@ -2090,6 +2245,20 @@ static void cxt5066_vostro_event(struct hda_codec *codec, unsigned int res)
        }
 }
 
+/* unsolicited event for jack sensing */
+static void cxt5066_ideapad_event(struct hda_codec *codec, unsigned int res)
+{
+       snd_printdd("CXT5066_ideapad: unsol event %x (%x)\n", res, res >> 26);
+       switch (res >> 26) {
+       case CONEXANT_HP_EVENT:
+               cxt5066_hp_automute(codec);
+               break;
+       case CONEXANT_MIC_EVENT:
+               cxt5066_ideapad_automic(codec);
+               break;
+       }
+}
+
 static const struct hda_input_mux cxt5066_analog_mic_boost = {
        .num_items = 5,
        .items = {
@@ -2101,6 +2270,23 @@ static const struct hda_input_mux cxt5066_analog_mic_boost = {
        },
 };
 
+static void cxt5066_set_mic_boost(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       snd_hda_codec_write_cache(codec, 0x17, 0,
+               AC_VERB_SET_AMP_GAIN_MUTE,
+               AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT |
+                       cxt5066_analog_mic_boost.items[spec->mic_boost].index);
+       if (spec->ideapad) {
+               /* adjust the internal mic as well...it is not through 0x17 */
+               snd_hda_codec_write_cache(codec, 0x23, 0,
+                       AC_VERB_SET_AMP_GAIN_MUTE,
+                       AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_INPUT |
+                               cxt5066_analog_mic_boost.
+                                       items[spec->mic_boost].index);
+       }
+}
+
 static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol,
                                           struct snd_ctl_elem_info *uinfo)
 {
@@ -2111,15 +2297,8 @@ static int cxt5066_mic_boost_mux_enum_get(struct snd_kcontrol *kcontrol,
                                          struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       int val;
-       hda_nid_t nid = kcontrol->private_value & 0xff;
-       int inout = (kcontrol->private_value & 0x100) ?
-               AC_AMP_GET_INPUT : AC_AMP_GET_OUTPUT;
-
-       val = snd_hda_codec_read(codec, nid, 0,
-               AC_VERB_GET_AMP_GAIN_MUTE, inout);
-
-       ucontrol->value.enumerated.item[0] = val & AC_AMP_GAIN;
+       struct conexant_spec *spec = codec->spec;
+       ucontrol->value.enumerated.item[0] = spec->mic_boost;
        return 0;
 }
 
@@ -2127,26 +2306,132 @@ static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol,
                                          struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct conexant_spec *spec = codec->spec;
        const struct hda_input_mux *imux = &cxt5066_analog_mic_boost;
        unsigned int idx;
-       hda_nid_t nid = kcontrol->private_value & 0xff;
-       int inout = (kcontrol->private_value & 0x100) ?
-               AC_AMP_SET_INPUT : AC_AMP_SET_OUTPUT;
+       idx = ucontrol->value.enumerated.item[0];
+       if (idx >= imux->num_items)
+               idx = imux->num_items - 1;
+
+       spec->mic_boost = idx;
+       if (!spec->dc_enable)
+               cxt5066_set_mic_boost(codec);
+       return 1;
+}
+
+static void cxt5066_enable_dc(struct hda_codec *codec)
+{
+       const struct hda_verb enable_dc_mode[] = {
+               /* disable gain */
+               {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+               /* switch to DC input */
+               {0x17, AC_VERB_SET_CONNECT_SEL, 3},
+               {}
+       };
+
+       /* configure as input source */
+       snd_hda_sequence_write(codec, enable_dc_mode);
+       cxt5066_olpc_select_mic(codec); /* also sets configured bias */
+}
+
+static void cxt5066_disable_dc(struct hda_codec *codec)
+{
+       /* reconfigure input source */
+       cxt5066_set_mic_boost(codec);
+       /* automic also selects the right mic if we're recording */
+       cxt5066_olpc_automic(codec);
+}
+
+static int cxt5066_olpc_dc_get(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct conexant_spec *spec = codec->spec;
+       ucontrol->value.integer.value[0] = spec->dc_enable;
+       return 0;
+}
 
-       if (!imux->num_items)
+static int cxt5066_olpc_dc_put(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct conexant_spec *spec = codec->spec;
+       int dc_enable = !!ucontrol->value.integer.value[0];
+
+       if (dc_enable == spec->dc_enable)
                return 0;
+
+       spec->dc_enable = dc_enable;
+       if (dc_enable)
+               cxt5066_enable_dc(codec);
+       else
+               cxt5066_disable_dc(codec);
+
+       return 1;
+}
+
+static int cxt5066_olpc_dc_bias_enum_info(struct snd_kcontrol *kcontrol,
+                                          struct snd_ctl_elem_info *uinfo)
+{
+       return snd_hda_input_mux_info(&cxt5066_olpc_dc_bias, uinfo);
+}
+
+static int cxt5066_olpc_dc_bias_enum_get(struct snd_kcontrol *kcontrol,
+                                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct conexant_spec *spec = codec->spec;
+       ucontrol->value.enumerated.item[0] = spec->dc_input_bias;
+       return 0;
+}
+
+static int cxt5066_olpc_dc_bias_enum_put(struct snd_kcontrol *kcontrol,
+                                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct conexant_spec *spec = codec->spec;
+       const struct hda_input_mux *imux = &cxt5066_analog_mic_boost;
+       unsigned int idx;
+
        idx = ucontrol->value.enumerated.item[0];
        if (idx >= imux->num_items)
                idx = imux->num_items - 1;
 
-       snd_hda_codec_write_cache(codec, nid, 0,
-               AC_VERB_SET_AMP_GAIN_MUTE,
-               AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | inout |
-                       imux->items[idx].index);
-
+       spec->dc_input_bias = idx;
+       if (spec->dc_enable)
+               cxt5066_set_olpc_dc_bias(codec);
        return 1;
 }
 
+static void cxt5066_olpc_capture_prepare(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       /* mark as recording and configure the microphone widget so that the
+        * recording LED comes on. */
+       spec->recording = 1;
+       cxt5066_olpc_select_mic(codec);
+}
+
+static void cxt5066_olpc_capture_cleanup(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       const struct hda_verb disable_mics[] = {
+               /* disable external mic, port B */
+               {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+
+               /* disble internal mic, port C */
+               {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+
+               /* disable DC capture, port F */
+               {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+               {},
+       };
+
+       snd_hda_sequence_write(codec, disable_mics);
+       spec->recording = 0;
+}
+
 static struct hda_input_mux cxt5066_capture_source = {
        .num_items = 4,
        .items = {
@@ -2187,6 +2472,7 @@ static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = {
                .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
                                  SNDRV_CTL_ELEM_ACCESS_TLV_READ |
                                  SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,
+               .subdevice = HDA_SUBDEV_AMP_FLAG,
                .info = snd_hda_mixer_amp_volume_info,
                .get = snd_hda_mixer_amp_volume_get,
                .put = snd_hda_mixer_amp_volume_put,
@@ -2198,6 +2484,24 @@ static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = {
        {}
 };
 
+static struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "DC Mode Enable Switch",
+               .info = snd_ctl_boolean_mono_info,
+               .get = cxt5066_olpc_dc_get,
+               .put = cxt5066_olpc_dc_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "DC Input Bias Enum",
+               .info = cxt5066_olpc_dc_bias_enum_info,
+               .get = cxt5066_olpc_dc_bias_enum_get,
+               .put = cxt5066_olpc_dc_bias_enum_put,
+       },
+       {}
+};
+
 static struct snd_kcontrol_new cxt5066_mixers[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -2210,11 +2514,10 @@ static struct snd_kcontrol_new cxt5066_mixers[] = {
 
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Ext Mic Boost Capture Enum",
+               .name = "Analog Mic Boost Capture Enum",
                .info = cxt5066_mic_boost_mux_enum_info,
                .get = cxt5066_mic_boost_mux_enum_get,
                .put = cxt5066_mic_boost_mux_enum_put,
-               .private_value = 0x17,
        },
 
        HDA_BIND_VOL("Capture Volume", &cxt5066_bind_capture_vol_others),
@@ -2296,10 +2599,10 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = {
        {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
 
        /* Port B: external microphone */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, CXT5066_OLPC_EXT_MIC_BIAS},
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
 
        /* Port C: internal microphone */
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
 
        /* Port D: unused */
        {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
@@ -2308,7 +2611,7 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = {
        {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
        {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
 
-       /* Port F: unused */
+       /* Port F: external DC input through microphone port */
        {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
 
        /* Port G: internal speakers */
@@ -2412,6 +2715,56 @@ static struct hda_verb cxt5066_init_verbs_vostro[] = {
        { } /* end */
 };
 
+static struct hda_verb cxt5066_init_verbs_ideapad[] = {
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */
+       {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */
+       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */
+
+       /* Speakers  */
+       {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
+
+       /* HP, Amp  */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
+
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
+
+       /* DAC1 */
+       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+       /* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       {0x14, AC_VERB_SET_CONNECT_SEL, 2},     /* default to internal mic */
+
+       /* Audio input selector */
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x2},
+       {0x17, AC_VERB_SET_CONNECT_SEL, 1},     /* route ext mic */
+
+       /* SPDIF route: PCM */
+       {0x20, AC_VERB_SET_CONNECT_SEL, 0x0},
+       {0x22, AC_VERB_SET_CONNECT_SEL, 0x0},
+
+       {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+
+       /* internal microphone */
+       {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable int mic */
+
+       /* EAPD */
+       {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
+
+       {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
+       { } /* end */
+};
+
 static struct hda_verb cxt5066_init_verbs_portd_lo[] = {
        {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
        { } /* end */
@@ -2428,8 +2781,24 @@ static int cxt5066_init(struct hda_codec *codec)
                cxt5066_hp_automute(codec);
                if (spec->dell_vostro)
                        cxt5066_vostro_automic(codec);
-               else
-                       cxt5066_automic(codec);
+               else if (spec->ideapad)
+                       cxt5066_ideapad_automic(codec);
+       }
+       cxt5066_set_mic_boost(codec);
+       return 0;
+}
+
+static int cxt5066_olpc_init(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       snd_printdd("CXT5066: init\n");
+       conexant_init(codec);
+       cxt5066_hp_automute(codec);
+       if (!spec->dc_enable) {
+               cxt5066_set_mic_boost(codec);
+               cxt5066_olpc_automic(codec);
+       } else {
+               cxt5066_enable_dc(codec);
        }
        return 0;
 }
@@ -2439,6 +2808,7 @@ enum {
        CXT5066_DELL_LAPTOP,    /* Dell Laptop */
        CXT5066_OLPC_XO_1_5,    /* OLPC XO 1.5 */
        CXT5066_DELL_VOSTO,     /* Dell Vostro 1015i */
+       CXT5066_IDEAPAD,        /* Lenovo IdeaPad U150 */
        CXT5066_MODELS
 };
 
@@ -2446,7 +2816,8 @@ 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_VOSTO]    = "dell-vostro",
+       [CXT5066_IDEAPAD]       = "ideapad",
 };
 
 static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
@@ -2456,6 +2827,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
                      CXT5066_DELL_LAPTOP),
        SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5),
        SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO),
+       SND_PCI_QUIRK(0x17aa, 0x3a0d, "ideapad", CXT5066_IDEAPAD),
        {}
 };
 
@@ -2470,7 +2842,7 @@ static int patch_cxt5066(struct hda_codec *codec)
        codec->spec = spec;
 
        codec->patch_ops = conexant_patch_ops;
-       codec->patch_ops.init = cxt5066_init;
+       codec->patch_ops.init = conexant_init;
 
        spec->dell_automute = 0;
        spec->multiout.max_channels = 2;
@@ -2483,7 +2855,6 @@ static int patch_cxt5066(struct hda_codec *codec)
        spec->input_mux = &cxt5066_capture_source;
 
        spec->port_d_mode = PIN_HP;
-       spec->ext_mic_bias = PIN_VREF80;
 
        spec->num_init_verbs = 1;
        spec->init_verbs[0] = cxt5066_init_verbs;
@@ -2510,20 +2881,28 @@ static int patch_cxt5066(struct hda_codec *codec)
                spec->dell_automute = 1;
                break;
        case CXT5066_OLPC_XO_1_5:
-               codec->patch_ops.unsol_event = cxt5066_unsol_event;
+               codec->patch_ops.init = cxt5066_olpc_init;
+               codec->patch_ops.unsol_event = cxt5066_olpc_unsol_event;
                spec->init_verbs[0] = cxt5066_init_verbs_olpc;
                spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc;
+               spec->mixers[spec->num_mixers++] = cxt5066_mixer_olpc_dc;
                spec->mixers[spec->num_mixers++] = cxt5066_mixers;
                spec->port_d_mode = 0;
-               spec->ext_mic_bias = CXT5066_OLPC_EXT_MIC_BIAS;
+               spec->mic_boost = 3; /* default 30dB gain */
 
                /* no S/PDIF out */
                spec->multiout.dig_out_nid = 0;
 
                /* input source automatically selected */
                spec->input_mux = NULL;
+
+               /* our capture hooks which allow us to turn on the microphone LED
+                * at the right time */
+               spec->capture_prepare = cxt5066_olpc_capture_prepare;
+               spec->capture_cleanup = cxt5066_olpc_capture_cleanup;
                break;
        case CXT5066_DELL_VOSTO:
+               codec->patch_ops.init = cxt5066_init;
                codec->patch_ops.unsol_event = cxt5066_vostro_event;
                spec->init_verbs[0] = cxt5066_init_verbs_vostro;
                spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc;
@@ -2531,11 +2910,28 @@ static int patch_cxt5066(struct hda_codec *codec)
                spec->mixers[spec->num_mixers++] = cxt5066_vostro_mixers;
                spec->port_d_mode = 0;
                spec->dell_vostro = 1;
+               spec->mic_boost = 3; /* default 30dB gain */
                snd_hda_attach_beep_device(codec, 0x13);
 
                /* no S/PDIF out */
                spec->multiout.dig_out_nid = 0;
 
+               /* input source automatically selected */
+               spec->input_mux = NULL;
+               break;
+       case CXT5066_IDEAPAD:
+               codec->patch_ops.init = cxt5066_init;
+               codec->patch_ops.unsol_event = cxt5066_ideapad_event;
+               spec->mixers[spec->num_mixers++] = cxt5066_mixer_master;
+               spec->mixers[spec->num_mixers++] = cxt5066_mixers;
+               spec->init_verbs[0] = cxt5066_init_verbs_ideapad;
+               spec->port_d_mode = 0;
+               spec->ideapad = 1;
+               spec->mic_boost = 2;    /* default 20dB gain */
+
+               /* no S/PDIF out */
+               spec->multiout.dig_out_nid = 0;
+
                /* input source automatically selected */
                spec->input_mux = NULL;
                break;
index da34095c707fd7b19fb33156248fc6461a7090e0..e8cbe216e912b1f85116733564f37162891cf81b 100644 (file)
@@ -131,8 +131,10 @@ enum {
 enum {
        ALC269_BASIC,
        ALC269_QUANTA_FL1,
-       ALC269_ASUS_AMIC,
-       ALC269_ASUS_DMIC,
+       ALC269_AMIC,
+       ALC269_DMIC,
+       ALC269VB_AMIC,
+       ALC269VB_DMIC,
        ALC269_FUJITSU,
        ALC269_LIFEBOOK,
        ALC269_AUTO,
@@ -207,8 +209,10 @@ enum {
        ALC882_ASUS_A7J,
        ALC882_ASUS_A7M,
        ALC885_MACPRO,
+       ALC885_MBA21,
        ALC885_MBP3,
        ALC885_MB5,
+       ALC885_MACMINI3,
        ALC885_IMAC24,
        ALC885_IMAC91,
        ALC883_3ST_2ch_DIG,
@@ -338,7 +342,7 @@ struct alc_spec {
        void (*init_hook)(struct hda_codec *codec);
        void (*unsol_event)(struct hda_codec *codec, unsigned int res);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-       void (*power_hook)(struct hda_codec *codec, int power);
+       void (*power_hook)(struct hda_codec *codec);
 #endif
 
        /* for pin sensing */
@@ -391,7 +395,7 @@ struct alc_config_preset {
        void (*init_hook)(struct hda_codec *);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        struct hda_amp_list *loopbacks;
-       void (*power_hook)(struct hda_codec *codec, int power);
+       void (*power_hook)(struct hda_codec *codec);
 #endif
 };
 
@@ -633,6 +637,7 @@ static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
 
 #define ALC_PIN_MODE(xname, nid, dir) \
        { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0,  \
+         .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
          .info = alc_pin_mode_info, \
          .get = alc_pin_mode_get, \
          .put = alc_pin_mode_put, \
@@ -684,6 +689,7 @@ static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
 }
 #define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
        { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0,  \
+         .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
          .info = alc_gpio_data_info, \
          .get = alc_gpio_data_get, \
          .put = alc_gpio_data_put, \
@@ -738,6 +744,7 @@ static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
 }
 #define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
        { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0,  \
+         .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
          .info = alc_spdif_ctrl_info, \
          .get = alc_spdif_ctrl_get, \
          .put = alc_spdif_ctrl_put, \
@@ -791,6 +798,7 @@ static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
 
 #define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
        { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0,  \
+         .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
          .info = alc_eapd_ctrl_info, \
          .get = alc_eapd_ctrl_get, \
          .put = alc_eapd_ctrl_put, \
@@ -837,27 +845,6 @@ static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
        spec->init_verbs[spec->num_init_verbs++] = verb;
 }
 
-#ifdef CONFIG_PROC_FS
-/*
- * hook for proc
- */
-static void print_realtek_coef(struct snd_info_buffer *buffer,
-                              struct hda_codec *codec, hda_nid_t nid)
-{
-       int coeff;
-
-       if (nid != 0x20)
-               return;
-       coeff = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0);
-       snd_iprintf(buffer, "  Processing Coefficient: 0x%02x\n", coeff);
-       coeff = snd_hda_codec_read(codec, nid, 0,
-                                  AC_VERB_GET_COEF_INDEX, 0);
-       snd_iprintf(buffer, "  Coefficient Index: 0x%02x\n", coeff);
-}
-#else
-#define print_realtek_coef     NULL
-#endif
-
 /*
  * set up from the preset table
  */
@@ -1162,6 +1149,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type)
                case 0x10ec0888:
                        alc888_coef_init(codec);
                        break;
+#if 0 /* XXX: This may cause the silent output on speaker on some machines */
                case 0x10ec0267:
                case 0x10ec0268:
                        snd_hda_codec_write(codec, 0x20, 0,
@@ -1174,6 +1162,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type)
                                            AC_VERB_SET_PROC_COEF,
                                            tmp | 0x3000);
                        break;
+#endif /* XXX */
                }
                break;
        }
@@ -1265,7 +1254,7 @@ static void alc_init_auto_mic(struct hda_codec *codec)
  */
 static int alc_subsystem_id(struct hda_codec *codec,
                            hda_nid_t porta, hda_nid_t porte,
-                           hda_nid_t portd)
+                           hda_nid_t portd, hda_nid_t porti)
 {
        unsigned int ass, tmp, i;
        unsigned nid;
@@ -1291,7 +1280,7 @@ static int alc_subsystem_id(struct hda_codec *codec,
        snd_printd("realtek: No valid SSID, "
                   "checking pincfg 0x%08x for NID 0x%x\n",
                   ass, nid);
-       if (!(ass & 1) && !(ass & 0x100000))
+       if (!(ass & 1))
                return 0;
        if ((ass >> 30) != 1)   /* no physical connection */
                return 0;
@@ -1351,6 +1340,8 @@ do_sku:
                        nid = porte;
                else if (tmp == 2)
                        nid = portd;
+               else if (tmp == 3)
+                       nid = porti;
                else
                        return 1;
                for (i = 0; i < spec->autocfg.line_outs; i++)
@@ -1365,9 +1356,10 @@ do_sku:
 }
 
 static void alc_ssid_check(struct hda_codec *codec,
-                          hda_nid_t porta, hda_nid_t porte, hda_nid_t portd)
+                          hda_nid_t porta, hda_nid_t porte,
+                          hda_nid_t portd, hda_nid_t porti)
 {
-       if (!alc_subsystem_id(codec, porta, porte, portd)) {
+       if (!alc_subsystem_id(codec, porta, porte, portd, porti)) {
                struct alc_spec *spec = codec->spec;
                snd_printd("realtek: "
                           "Enable default setup for auto mode as fallback\n");
@@ -1840,14 +1832,6 @@ static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
        spec->autocfg.speaker_pins[2] = 0x1b;
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static void alc889_power_eapd(struct hda_codec *codec, int power)
-{
-       set_eapd(codec, 0x14, power);
-       set_eapd(codec, 0x15, power);
-}
-#endif
-
 /*
  * ALC880 3-stack model
  *
@@ -2450,6 +2434,15 @@ static const char *alc_slave_sws[] = {
  * build control elements
  */
 
+#define NID_MAPPING            (-1)
+
+#define SUBDEV_SPEAKER_                (0 << 6)
+#define SUBDEV_HP_             (1 << 6)
+#define SUBDEV_LINE_           (2 << 6)
+#define SUBDEV_SPEAKER(x)      (SUBDEV_SPEAKER_ | ((x) & 0x3f))
+#define SUBDEV_HP(x)           (SUBDEV_HP_ | ((x) & 0x3f))
+#define SUBDEV_LINE(x)         (SUBDEV_LINE_ | ((x) & 0x3f))
+
 static void alc_free_kctls(struct hda_codec *codec);
 
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
@@ -2464,8 +2457,11 @@ static struct snd_kcontrol_new alc_beep_mixer[] = {
 static int alc_build_controls(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       int err;
-       int i;
+       struct snd_kcontrol *kctl;
+       struct snd_kcontrol_new *knew;
+       int i, j, err;
+       unsigned int u;
+       hda_nid_t nid;
 
        for (i = 0; i < spec->num_mixers; i++) {
                err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
@@ -2506,8 +2502,7 @@ static int alc_build_controls(struct hda_codec *codec)
                        if (!kctl)
                                return -ENOMEM;
                        kctl->private_value = spec->beep_amp;
-                       err = snd_hda_ctl_add(codec,
-                                       get_amp_nid_(spec->beep_amp), kctl);
+                       err = snd_hda_ctl_add(codec, 0, kctl);
                        if (err < 0)
                                return err;
                }
@@ -2534,6 +2529,75 @@ static int alc_build_controls(struct hda_codec *codec)
        }
 
        alc_free_kctls(codec); /* no longer needed */
+
+       /* assign Capture Source enums to NID */
+       kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
+       if (!kctl)
+               kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
+       for (i = 0; kctl && i < kctl->count; i++) {
+               hda_nid_t *nids = spec->capsrc_nids;
+               if (!nids)
+                       nids = spec->adc_nids;
+               err = snd_hda_add_nid(codec, kctl, i, nids[i]);
+               if (err < 0)
+                       return err;
+       }
+       if (spec->cap_mixer) {
+               const char *kname = kctl ? kctl->id.name : NULL;
+               for (knew = spec->cap_mixer; knew->name; knew++) {
+                       if (kname && strcmp(knew->name, kname) == 0)
+                               continue;
+                       kctl = snd_hda_find_mixer_ctl(codec, knew->name);
+                       for (i = 0; kctl && i < kctl->count; i++) {
+                               err = snd_hda_add_nid(codec, kctl, i,
+                                                     spec->adc_nids[i]);
+                               if (err < 0)
+                                       return err;
+                       }
+               }
+       }
+
+       /* other nid->control mapping */
+       for (i = 0; i < spec->num_mixers; i++) {
+               for (knew = spec->mixers[i]; knew->name; knew++) {
+                       if (knew->iface != NID_MAPPING)
+                               continue;
+                       kctl = snd_hda_find_mixer_ctl(codec, knew->name);
+                       if (kctl == NULL)
+                               continue;
+                       u = knew->subdevice;
+                       for (j = 0; j < 4; j++, u >>= 8) {
+                               nid = u & 0x3f;
+                               if (nid == 0)
+                                       continue;
+                               switch (u & 0xc0) {
+                               case SUBDEV_SPEAKER_:
+                                       nid = spec->autocfg.speaker_pins[nid];
+                                       break;
+                               case SUBDEV_LINE_:
+                                       nid = spec->autocfg.line_out_pins[nid];
+                                       break;
+                               case SUBDEV_HP_:
+                                       nid = spec->autocfg.hp_pins[nid];
+                                       break;
+                               default:
+                                       continue;
+                               }
+                               err = snd_hda_add_nid(codec, kctl, 0, nid);
+                               if (err < 0)
+                                       return err;
+                       }
+                       u = knew->private_value;
+                       for (j = 0; j < 4; j++, u >>= 8) {
+                               nid = u & 0xff;
+                               if (nid == 0)
+                                       continue;
+                               err = snd_hda_add_nid(codec, kctl, 0, nid);
+                               if (err < 0)
+                                       return err;
+                       }
+               }
+       }
        return 0;
 }
 
@@ -3616,6 +3680,11 @@ static int alc_build_pcms(struct hda_codec *codec)
        return 0;
 }
 
+static inline void alc_shutup(struct hda_codec *codec)
+{
+       snd_hda_shutup_pins(codec);
+}
+
 static void alc_free_kctls(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
@@ -3636,17 +3705,44 @@ static void alc_free(struct hda_codec *codec)
        if (!spec)
                return;
 
+       alc_shutup(codec);
        alc_free_kctls(codec);
        kfree(spec);
        snd_hda_detach_beep_device(codec);
 }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
+static void alc_power_eapd(struct hda_codec *codec)
+{
+       /* We currently only handle front, HP */
+       switch (codec->vendor_id) {
+       case 0x10ec0260:
+               set_eapd(codec, 0x0f, 0);
+               set_eapd(codec, 0x10, 0);
+               break;
+       case 0x10ec0262:
+       case 0x10ec0267:
+       case 0x10ec0268:
+       case 0x10ec0269:
+       case 0x10ec0270:
+       case 0x10ec0272:
+       case 0x10ec0660:
+       case 0x10ec0662:
+       case 0x10ec0663:
+       case 0x10ec0862:
+       case 0x10ec0889:
+               set_eapd(codec, 0x14, 0);
+               set_eapd(codec, 0x15, 0);
+               break;
+       }
+}
+
 static int alc_suspend(struct hda_codec *codec, pm_message_t state)
 {
        struct alc_spec *spec = codec->spec;
+       alc_shutup(codec);
        if (spec && spec->power_hook)
-               spec->power_hook(codec, 0);
+               spec->power_hook(codec);
        return 0;
 }
 #endif
@@ -3654,16 +3750,9 @@ static int alc_suspend(struct hda_codec *codec, pm_message_t state)
 #ifdef SND_HDA_NEEDS_RESUME
 static int alc_resume(struct hda_codec *codec)
 {
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       struct alc_spec *spec = codec->spec;
-#endif
        codec->patch_ops.init(codec);
        snd_hda_codec_resume_amp(codec);
        snd_hda_codec_resume_cache(codec);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       if (spec && spec->power_hook)
-               spec->power_hook(codec, 1);
-#endif
        return 0;
 }
 #endif
@@ -3683,6 +3772,7 @@ static struct hda_codec_ops alc_patch_ops = {
        .suspend = alc_suspend,
        .check_power_status = alc_check_power_status,
 #endif
+       .reboot_notify = alc_shutup,
 };
 
 
@@ -3839,6 +3929,7 @@ static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
 #define PIN_CTL_TEST(xname,nid) {                      \
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,    \
                        .name = xname,                 \
+                       .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
                        .info = alc_test_pin_ctl_info, \
                        .get = alc_test_pin_ctl_get,   \
                        .put = alc_test_pin_ctl_put,   \
@@ -3848,6 +3939,7 @@ static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
 #define PIN_SRC_TEST(xname,nid) {                      \
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,    \
                        .name = xname,                 \
+                       .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
                        .info = alc_test_pin_src_info, \
                        .get = alc_test_pin_src_get,   \
                        .put = alc_test_pin_src_put,   \
@@ -4387,7 +4479,7 @@ static int add_control(struct alc_spec *spec, int type, const char *name,
        if (!knew->name)
                return -ENOMEM;
        if (get_amp_nid_(val))
-               knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val);
+               knew->subdevice = HDA_SUBDEV_AMP_FLAG;
        knew->private_value = val;
        return 0;
 }
@@ -4770,7 +4862,7 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
        spec->num_mux_defs = 1;
        spec->input_mux = &spec->private_imux[0];
 
-       alc_ssid_check(codec, 0x15, 0x1b, 0x14);
+       alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
 
        return 1;
 }
@@ -4974,7 +5066,6 @@ static int patch_alc880(struct hda_codec *codec)
        if (!spec->loopback.amplist)
                spec->loopback.amplist = alc880_loopbacks;
 #endif
-       codec->proc_widget_hook = print_realtek_coef;
 
        return 0;
 }
@@ -5182,6 +5273,7 @@ static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Master Playback Switch",
+               .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
                .info = snd_ctl_boolean_mono_info,
                .get = alc260_hp_master_sw_get,
                .put = alc260_hp_master_sw_put,
@@ -5220,6 +5312,7 @@ static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Master Playback Switch",
+               .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
                .info = snd_ctl_boolean_mono_info,
                .get = alc260_hp_master_sw_get,
                .put = alc260_hp_master_sw_put,
@@ -6303,7 +6396,7 @@ static int alc260_parse_auto_config(struct hda_codec *codec)
        spec->num_mux_defs = 1;
        spec->input_mux = &spec->private_imux[0];
 
-       alc_ssid_check(codec, 0x10, 0x15, 0x0f);
+       alc_ssid_check(codec, 0x10, 0x15, 0x0f, 0);
 
        return 1;
 }
@@ -6582,7 +6675,6 @@ static int patch_alc260(struct hda_codec *codec)
        if (!spec->loopback.amplist)
                spec->loopback.amplist = alc260_loopbacks;
 #endif
-       codec->proc_widget_hook = print_realtek_coef;
 
        return 0;
 }
@@ -6664,6 +6756,14 @@ static struct hda_input_mux mb5_capture_source = {
        },
 };
 
+static struct hda_input_mux macmini3_capture_source = {
+       .num_items = 2,
+       .items = {
+               { "Line", 0x2 },
+               { "CD", 0x4 },
+       },
+};
+
 static struct hda_input_mux alc883_3stack_6ch_intel = {
        .num_items = 4,
        .items = {
@@ -6852,6 +6952,13 @@ static struct hda_channel_mode alc882_sixstack_modes[2] = {
        { 8, alc882_sixstack_ch8_init },
 };
 
+
+/* Macbook Air 2,1 */
+
+static struct hda_channel_mode alc885_mba21_ch_modes[1] = {
+      { 2, NULL },
+};
+
 /*
  * macbook pro ALC885 can switch LineIn to LineOut without losing Mic
  */
@@ -6912,6 +7019,7 @@ static struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
        { 6, alc885_mb5_ch6_init },
 };
 
+#define alc885_macmini3_6ch_modes      alc885_mb5_6ch_modes
 
 /*
  * 2ch mode
@@ -7123,6 +7231,15 @@ static struct snd_kcontrol_new alc882_base_mixer[] = {
        { } /* end */
 };
 
+/* Macbook Air 2,1 same control for HP and internal Speaker */
+
+static struct snd_kcontrol_new alc885_mba21_mixer[] = {
+      HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
+      HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_OUTPUT),
+     { }
+};
+
+
 static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
        HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
        HDA_BIND_MUTE   ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
@@ -7156,6 +7273,21 @@ static struct snd_kcontrol_new alc885_mb5_mixer[] = {
        { } /* end */
 };
 
+static struct snd_kcontrol_new alc885_macmini3_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE   ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE   ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE   ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE   ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
+       HDA_CODEC_MUTE  ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT),
+       { } /* end */
+};
+
 static struct snd_kcontrol_new alc885_imac91_mixer[] = {
        HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
        HDA_BIND_MUTE   ("Line-Out Playback Switch", 0x0c, 0x02, HDA_INPUT),
@@ -7247,29 +7379,18 @@ static struct snd_kcontrol_new alc882_chmode_mixer[] = {
 
 static struct hda_verb alc882_base_init_verbs[] = {
        /* Front mixer: unmute input/output amp left and right (volume = 0) */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
        {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
        {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
        /* Rear mixer */
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
        {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
        {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
        /* CLFE mixer */
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
        {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
        {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
        /* Side mixer */
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
        {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
        {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
 
-       /* mute analog input loopbacks */
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-
        /* Front Pin: output 0 (0x0c) */
        {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
        {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
@@ -7306,14 +7427,8 @@ static struct hda_verb alc882_base_init_verbs[] = {
        /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
        /* Input mixer2 */
        {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
        /* Input mixer3 */
        {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
        /* ADC2: mute amp left and right */
        {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
        {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
@@ -7357,26 +7472,17 @@ static struct hda_verb alc_hp15_unsol_verbs[] = {
 
 static struct hda_verb alc885_init_verbs[] = {
        /* Front mixer: unmute input/output amp left and right (volume = 0) */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
        /* Rear mixer */
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
        /* CLFE mixer */
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
        /* Side mixer */
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-
-       /* mute analog input loopbacks */
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 
        /* Front HP Pin: output 0 (0x0c) */
        {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -7410,17 +7516,11 @@ static struct hda_verb alc885_init_verbs[] = {
 
        /* Mixer elements: 0x18, , 0x1a, 0x1b */
        /* Input mixer1 */
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        /* Input mixer2 */
        {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
        /* Input mixer3 */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        /* ADC2: mute amp left and right */
        {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
        /* ADC3: mute amp left and right */
@@ -7562,6 +7662,76 @@ static struct hda_verb alc885_mb5_init_verbs[] = {
        { }
 };
 
+/* Macmini 3,1 */
+static struct hda_verb alc885_macmini3_init_verbs[] = {
+       /* DACs */
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* Front mixer */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* Surround mixer */
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* LFE mixer */
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* HP mixer */
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* Front Pin (0x0c) */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* LFE Pin (0x0e) */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
+       /* HP Pin (0x0f) */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+       /* Line In pin */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       { }
+};
+
+
+static struct hda_verb alc885_mba21_init_verbs[] = {
+       /*Internal and HP Speaker Mixer*/
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       /*Internal Speaker Pin (0x0c)*/
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* HP Pin: output 0 (0x0e) */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
+       /* Line in (is hp when jack connected)*/
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+
+       { }
+ };
+
+
 /* Macbook Pro rev3 */
 static struct hda_verb alc885_mbp3_init_verbs[] = {
        /* Front mixer: unmute input/output amp left and right (volume = 0) */
@@ -7724,54 +7894,35 @@ static void alc885_imac24_setup(struct hda_codec *codec)
        spec->autocfg.speaker_pins[1] = 0x1a;
 }
 
-static void alc885_mbp3_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-}
+#define alc885_mb5_setup       alc885_imac24_setup
+#define alc885_macmini3_setup  alc885_imac24_setup
 
-static void alc885_mb5_automute(struct hda_codec *codec)
+/* Macbook Air 2,1 */
+static void alc885_mba21_setup(struct hda_codec *codec)
 {
-       unsigned int present;
-
-       present = snd_hda_codec_read(codec, 0x14, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-       snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-       snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+       struct alc_spec *spec = codec->spec;
 
+       spec->autocfg.hp_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[0] = 0x18;
 }
 
-static void alc885_mb5_unsol_event(struct hda_codec *codec,
-                                   unsigned int res)
-{
-       /* Headphone insertion or removal. */
-       if ((res >> 26) == ALC880_HP_EVENT)
-               alc885_mb5_automute(codec);
-}
 
-static void alc885_imac91_automute(struct hda_codec *codec)
-{
-       unsigned int present;
 
-       present = snd_hda_codec_read(codec, 0x14, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-       snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-       snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+static void alc885_mbp3_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
 
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
 }
 
-static void alc885_imac91_unsol_event(struct hda_codec *codec,
-                                   unsigned int res)
+static void alc885_imac91_setup(struct hda_codec *codec)
 {
-       /* Headphone insertion or removal. */
-       if ((res >> 26) == ALC880_HP_EVENT)
-               alc885_imac91_automute(codec);
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[1] = 0x1a;
 }
 
 static struct hda_verb alc882_targa_verbs[] = {
@@ -7906,18 +8057,6 @@ static struct hda_verb alc883_auto_init_verbs[] = {
        {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
        {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 
-       /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
-        * mixer widget
-        * Note: PASD motherboards uses the Line In 2 as the input for
-        * front panel mic (mic 2)
-        */
-       /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-
        /*
         * Set up output mixers (0x0c - 0x0f)
         */
@@ -7942,16 +8081,9 @@ static struct hda_verb alc883_auto_init_verbs[] = {
        /* FIXME: use matrix-type input source selection */
        /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
        /* Input mixer2 */
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        /* Input mixer3 */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
-
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        { }
 };
 
@@ -8938,6 +9070,8 @@ static const char *alc882_models[ALC882_MODEL_LAST] = {
        [ALC882_ASUS_A7M]       = "asus-a7m",
        [ALC885_MACPRO]         = "macpro",
        [ALC885_MB5]            = "mb5",
+       [ALC885_MACMINI3]       = "macmini3",
+       [ALC885_MBA21]          = "mba21",
        [ALC885_MBP3]           = "mbp3",
        [ALC885_IMAC24]         = "imac24",
        [ALC885_IMAC91]         = "imac91",
@@ -9121,6 +9255,7 @@ static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
         */
        SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5),
        SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5),
+       SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC885_MACMINI3),
        {} /* terminator */
 };
 
@@ -9172,6 +9307,18 @@ static struct alc_config_preset alc882_presets[] = {
                .input_mux = &alc882_capture_source,
                .dig_out_nid = ALC882_DIGOUT_NID,
        },
+          [ALC885_MBA21] = {
+                       .mixers = { alc885_mba21_mixer },
+                       .init_verbs = { alc885_mba21_init_verbs, alc880_gpio1_init_verbs },
+                       .num_dacs = 2,
+                       .dac_nids = alc882_dac_nids,
+                       .channel_mode = alc885_mba21_ch_modes,
+                       .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
+                       .input_mux = &alc882_capture_source,
+                       .unsol_event = alc_automute_amp_unsol_event,
+                       .setup = alc885_mba21_setup,
+                       .init_hook = alc_automute_amp,
+       },
        [ALC885_MBP3] = {
                .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
                .init_verbs = { alc885_mbp3_init_verbs,
@@ -9199,8 +9346,24 @@ static struct alc_config_preset alc882_presets[] = {
                .input_mux = &mb5_capture_source,
                .dig_out_nid = ALC882_DIGOUT_NID,
                .dig_in_nid = ALC882_DIGIN_NID,
-               .unsol_event = alc885_mb5_unsol_event,
-               .init_hook = alc885_mb5_automute,
+               .unsol_event = alc_automute_amp_unsol_event,
+               .setup = alc885_mb5_setup,
+               .init_hook = alc_automute_amp,
+       },
+       [ALC885_MACMINI3] = {
+               .mixers = { alc885_macmini3_mixer, alc882_chmode_mixer },
+               .init_verbs = { alc885_macmini3_init_verbs,
+                               alc880_gpio1_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+               .dac_nids = alc882_dac_nids,
+               .channel_mode = alc885_macmini3_6ch_modes,
+               .num_channel_mode = ARRAY_SIZE(alc885_macmini3_6ch_modes),
+               .input_mux = &macmini3_capture_source,
+               .dig_out_nid = ALC882_DIGOUT_NID,
+               .dig_in_nid = ALC882_DIGIN_NID,
+               .unsol_event = alc_automute_amp_unsol_event,
+               .setup = alc885_macmini3_setup,
+               .init_hook = alc_automute_amp,
        },
        [ALC885_MACPRO] = {
                .mixers = { alc882_macpro_mixer },
@@ -9239,8 +9402,9 @@ static struct alc_config_preset alc882_presets[] = {
                .input_mux = &alc882_capture_source,
                .dig_out_nid = ALC882_DIGOUT_NID,
                .dig_in_nid = ALC882_DIGIN_NID,
-               .unsol_event = alc885_imac91_unsol_event,
-               .init_hook = alc885_imac91_automute,
+               .unsol_event = alc_automute_amp_unsol_event,
+               .setup = alc885_imac91_setup,
+               .init_hook = alc_automute_amp,
        },
        [ALC882_TARGA] = {
                .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
@@ -9528,7 +9692,7 @@ static struct alc_config_preset alc882_presets[] = {
                .setup = alc889_acer_aspire_8930g_setup,
                .init_hook = alc_automute_amp,
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-               .power_hook = alc889_power_eapd,
+               .power_hook = alc_power_eapd,
 #endif
        },
        [ALC888_ACER_ASPIRE_7730G] = {
@@ -10063,7 +10227,7 @@ static int alc882_parse_auto_config(struct hda_codec *codec)
        spec->num_mux_defs = 1;
        spec->input_mux = &spec->private_imux[0];
 
-       alc_ssid_check(codec, 0x15, 0x1b, 0x14);
+       alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
 
        err = alc_auto_add_mic_boost(codec);
        if (err < 0)
@@ -10201,7 +10365,6 @@ static int patch_alc882(struct hda_codec *codec)
        if (!spec->loopback.amplist)
                spec->loopback.amplist = alc882_loopbacks;
 #endif
-       codec->proc_widget_hook = print_realtek_coef;
 
        return 0;
 }
@@ -10324,8 +10487,14 @@ static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
                .info = snd_ctl_boolean_mono_info,              \
                .get = alc262_hp_master_sw_get,                 \
                .put = alc262_hp_master_sw_put,                 \
+       }, \
+       {                                                       \
+               .iface = NID_MAPPING,                           \
+               .name = "Master Playback Switch",               \
+               .private_value = 0x15 | (0x16 << 8) | (0x1b << 16),     \
        }
 
+
 static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
        ALC262_HP_MASTER_SWITCH,
        HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
@@ -10483,6 +10652,12 @@ static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol,
                .info = snd_ctl_boolean_mono_info,              \
                .get = alc262_hippo_master_sw_get,              \
                .put = alc262_hippo_master_sw_put,              \
+       },                                                      \
+       {                                                       \
+               .iface = NID_MAPPING,                           \
+               .name = "Master Playback Switch",               \
+               .subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \
+                            (SUBDEV_SPEAKER(0) << 16), \
        }
 
 static struct snd_kcontrol_new alc262_hippo_mixer[] = {
@@ -10963,11 +11138,17 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Master Playback Switch",
+               .subdevice = HDA_SUBDEV_AMP_FLAG,
                .info = snd_hda_mixer_amp_switch_info,
                .get = snd_hda_mixer_amp_switch_get,
                .put = alc262_fujitsu_master_sw_put,
                .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
        },
+       {
+               .iface = NID_MAPPING,
+               .name = "Master Playback Switch",
+               .private_value = 0x1b,
+       },
        HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
@@ -10998,6 +11179,7 @@ static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Master Playback Switch",
+               .subdevice = HDA_SUBDEV_AMP_FLAG,
                .info = snd_hda_mixer_amp_switch_info,
                .get = snd_hda_mixer_amp_switch_get,
                .put = alc262_lenovo_3000_master_sw_put,
@@ -11152,6 +11334,11 @@ static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
                .get = alc_mux_enum_get,
                .put = alc262_ultra_mux_enum_put,
        },
+       {
+               .iface = NID_MAPPING,
+               .name = "Capture Source",
+               .private_value = 0x15,
+       },
        { } /* end */
 };
 
@@ -11598,7 +11785,7 @@ static int alc262_parse_auto_config(struct hda_codec *codec)
        if (err < 0)
                return err;
 
-       alc_ssid_check(codec, 0x15, 0x14, 0x1b);
+       alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
 
        return 1;
 }
@@ -12041,7 +12228,6 @@ static int patch_alc262(struct hda_codec *codec)
        if (!spec->loopback.amplist)
                spec->loopback.amplist = alc262_loopbacks;
 #endif
-       codec->proc_widget_hook = print_realtek_coef;
 
        return 0;
 }
@@ -12170,6 +12356,7 @@ static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Master Playback Switch",
+               .subdevice = HDA_SUBDEV_AMP_FLAG,
                .info = snd_hda_mixer_amp_switch_info,
                .get = snd_hda_mixer_amp_switch_get,
                .put = alc268_acer_master_sw_put,
@@ -12185,6 +12372,7 @@ static struct snd_kcontrol_new alc268_acer_mixer[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Master Playback Switch",
+               .subdevice = HDA_SUBDEV_AMP_FLAG,
                .info = snd_hda_mixer_amp_switch_info,
                .get = snd_hda_mixer_amp_switch_get,
                .put = alc268_acer_master_sw_put,
@@ -12202,6 +12390,7 @@ static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Master Playback Switch",
+               .subdevice = HDA_SUBDEV_AMP_FLAG,
                .info = snd_hda_mixer_amp_switch_info,
                .get = snd_hda_mixer_amp_switch_get,
                .put = alc268_acer_master_sw_put,
@@ -12547,7 +12736,6 @@ static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
                dac = 0x02;
                break;
        case 0x15:
-       case 0x21:
                dac = 0x03;
                break;
        default:
@@ -12768,7 +12956,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
        if (err < 0)
                return err;
 
-       alc_ssid_check(codec, 0x15, 0x1b, 0x14);
+       alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
 
        return 1;
 }
@@ -13105,8 +13293,6 @@ static int patch_alc268(struct hda_codec *codec)
        if (board_config == ALC268_AUTO)
                spec->init_hook = alc268_auto_init;
 
-       codec->proc_widget_hook = print_realtek_coef;
-
        return 0;
 }
 
@@ -13126,6 +13312,15 @@ static hda_nid_t alc269_capsrc_nids[1] = {
        0x23,
 };
 
+static hda_nid_t alc269vb_adc_nids[1] = {
+       /* ADC1 */
+       0x09,
+};
+
+static hda_nid_t alc269vb_capsrc_nids[1] = {
+       0x22,
+};
+
 /* NOTE: ADC2 (0x07) is connected from a recording *MIXER* (0x24),
  *       not a mux!
  */
@@ -13155,6 +13350,7 @@ static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Master Playback Switch",
+               .subdevice = HDA_SUBDEV_AMP_FLAG,
                .info = snd_hda_mixer_amp_switch_info,
                .get = snd_hda_mixer_amp_switch_get,
                .put = alc268_acer_master_sw_put,
@@ -13175,6 +13371,7 @@ static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Master Playback Switch",
+               .subdevice = HDA_SUBDEV_AMP_FLAG,
                .info = snd_hda_mixer_amp_switch_info,
                .get = snd_hda_mixer_amp_switch_get,
                .put = alc268_acer_master_sw_put,
@@ -13192,7 +13389,7 @@ static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
        { }
 };
 
-static struct snd_kcontrol_new alc269_eeepc_mixer[] = {
+static struct snd_kcontrol_new alc269_laptop_mixer[] = {
        HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
@@ -13200,16 +13397,47 @@ static struct snd_kcontrol_new alc269_eeepc_mixer[] = {
        { } /* end */
 };
 
+static struct snd_kcontrol_new alc269vb_laptop_mixer[] = {
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+       { } /* end */
+};
+
 /* capture mixer elements */
-static struct snd_kcontrol_new alc269_epc_capture_mixer[] = {
+static struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = {
+       HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("IntMic Boost", 0x19, 0, HDA_INPUT),
+       { } /* end */
+};
+
+static struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = {
        HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
        { } /* end */
 };
 
+static struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = {
+       HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("IntMic Boost", 0x19, 0, HDA_INPUT),
+       { } /* end */
+};
+
+static struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = {
+       HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       { } /* end */
+};
+
 /* FSC amilo */
-#define alc269_fujitsu_mixer   alc269_eeepc_mixer
+#define alc269_fujitsu_mixer   alc269_laptop_mixer
 
 static struct hda_verb alc269_quanta_fl1_verbs[] = {
        {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
@@ -13352,7 +13580,7 @@ static void alc269_lifebook_init_hook(struct hda_codec *codec)
        alc269_lifebook_mic_autoswitch(codec);
 }
 
-static struct hda_verb alc269_eeepc_dmic_init_verbs[] = {
+static struct hda_verb alc269_laptop_dmic_init_verbs[] = {
        {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
        {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
        {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
@@ -13363,7 +13591,7 @@ static struct hda_verb alc269_eeepc_dmic_init_verbs[] = {
        {}
 };
 
-static struct hda_verb alc269_eeepc_amic_init_verbs[] = {
+static struct hda_verb alc269_laptop_amic_init_verbs[] = {
        {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
        {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
        {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
@@ -13373,6 +13601,28 @@ static struct hda_verb alc269_eeepc_amic_init_verbs[] = {
        {}
 };
 
+static struct hda_verb alc269vb_laptop_dmic_init_verbs[] = {
+       {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {0x22, AC_VERB_SET_CONNECT_SEL, 0x06},
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+       {}
+};
+
+static struct hda_verb alc269vb_laptop_amic_init_verbs[] = {
+       {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+       {}
+};
+
 /* toggle speaker-output according to the hp-jack state */
 static void alc269_speaker_automute(struct hda_codec *codec)
 {
@@ -13390,7 +13640,7 @@ static void alc269_speaker_automute(struct hda_codec *codec)
 }
 
 /* unsolicited event for HP jack sensing */
-static void alc269_eeepc_unsol_event(struct hda_codec *codec,
+static void alc269_laptop_unsol_event(struct hda_codec *codec,
                                     unsigned int res)
 {
        switch (res >> 26) {
@@ -13403,7 +13653,7 @@ static void alc269_eeepc_unsol_event(struct hda_codec *codec,
        }
 }
 
-static void alc269_eeepc_dmic_setup(struct hda_codec *codec)
+static void alc269_laptop_dmic_setup(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
        spec->ext_mic.pin = 0x18;
@@ -13413,7 +13663,17 @@ static void alc269_eeepc_dmic_setup(struct hda_codec *codec)
        spec->auto_mic = 1;
 }
 
-static void alc269_eeepc_amic_setup(struct hda_codec *codec)
+static void alc269vb_laptop_dmic_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       spec->ext_mic.pin = 0x18;
+       spec->ext_mic.mux_idx = 0;
+       spec->int_mic.pin = 0x12;
+       spec->int_mic.mux_idx = 6;
+       spec->auto_mic = 1;
+}
+
+static void alc269_laptop_amic_setup(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
        spec->ext_mic.pin = 0x18;
@@ -13423,7 +13683,7 @@ static void alc269_eeepc_amic_setup(struct hda_codec *codec)
        spec->auto_mic = 1;
 }
 
-static void alc269_eeepc_inithook(struct hda_codec *codec)
+static void alc269_laptop_inithook(struct hda_codec *codec)
 {
        alc269_speaker_automute(codec);
        alc_mic_automute(codec);
@@ -13436,22 +13696,10 @@ static struct hda_verb alc269_init_verbs[] = {
        /*
         * Unmute ADC0 and set the default input to mic-in
         */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-       /* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the
-        * analog-loopback mixer widget
-        * Note: PASD motherboards uses the Line In 2 as the input for
-        * front panel mic (mic 2)
-        */
-       /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 
        /*
-        * Set up output mixers (0x0c - 0x0e)
+        * Set up output mixers (0x02 - 0x03)
         */
        /* set vol=0 to output mixers */
        {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
@@ -13476,26 +13724,57 @@ static struct hda_verb alc269_init_verbs[] = {
 
        {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
        {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* FIXME: use Mux-type input source selection */
+       /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
+       /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+       {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
 
-       /* FIXME: use matrix-type input source selection */
+       /* set EAPD */
+       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
+       { }
+};
+
+static struct hda_verb alc269vb_init_verbs[] = {
+       /*
+        * Unmute ADC0 and set the default input to mic-in
+        */
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+       /*
+        * Set up output mixers (0x02 - 0x03)
+        */
+       /* set vol=0 to output mixers */
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+       /* set up input amps for analog loopback */
+       /* Amp Indices: DAC = 0, mixer = 1 */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+       /* FIXME: use Mux-type input source selection */
        /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
        /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x22, AC_VERB_SET_CONNECT_SEL, 0x00},
 
        /* set EAPD */
        {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
-       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
        { }
 };
 
@@ -13543,6 +13822,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
        struct alc_spec *spec = codec->spec;
        int err;
        static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
+       hda_nid_t real_capsrc_nids;
 
        err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
                                           alc269_ignore);
@@ -13564,11 +13844,20 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
        if (spec->kctls.list)
                add_mixer(spec, spec->kctls.list);
 
-       add_verb(spec, alc269_init_verbs);
+       if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010) {
+               add_verb(spec, alc269vb_init_verbs);
+               real_capsrc_nids = alc269vb_capsrc_nids[0];
+               alc_ssid_check(codec, 0, 0x1b, 0x14, 0x21);
+       } else {
+               add_verb(spec, alc269_init_verbs);
+               real_capsrc_nids = alc269_capsrc_nids[0];
+               alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
+       }
+
        spec->num_mux_defs = 1;
        spec->input_mux = &spec->private_imux[0];
        /* set default input source */
-       snd_hda_codec_write_cache(codec, alc269_capsrc_nids[0],
+       snd_hda_codec_write_cache(codec, real_capsrc_nids,
                                  0, AC_VERB_SET_CONNECT_SEL,
                                  spec->input_mux->items[0].index);
 
@@ -13579,8 +13868,6 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
        if (!spec->cap_mixer && !spec->no_analog)
                set_capture_mixer(codec);
 
-       alc_ssid_check(codec, 0x15, 0x1b, 0x14);
-
        return 1;
 }
 
@@ -13606,8 +13893,8 @@ static void alc269_auto_init(struct hda_codec *codec)
 static const char *alc269_models[ALC269_MODEL_LAST] = {
        [ALC269_BASIC]                  = "basic",
        [ALC269_QUANTA_FL1]             = "quanta",
-       [ALC269_ASUS_AMIC]              = "asus-amic",
-       [ALC269_ASUS_DMIC]              = "asus-dmic",
+       [ALC269_AMIC]                   = "laptop-amic",
+       [ALC269_DMIC]                   = "laptop-dmic",
        [ALC269_FUJITSU]                = "fujitsu",
        [ALC269_LIFEBOOK]               = "lifebook",
        [ALC269_AUTO]                   = "auto",
@@ -13616,43 +13903,57 @@ static const char *alc269_models[ALC269_MODEL_LAST] = {
 static struct snd_pci_quirk alc269_cfg_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
        SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
-                     ALC269_ASUS_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_ASUS_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80JT", ALC269_ASUS_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_ASUS_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82Jv", ALC269_ASUS_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_ASUS_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_ASUS_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_ASUS_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_ASUS_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_ASUS_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_ASUS_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_ASUS_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_ASUS_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_ASUS_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_ASUS_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_ASUS_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_ASUS_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_ASUS_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_ASUS_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_ASUS_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_ASUS_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_ASUS_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_ASUS_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_ASUS_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_ASUS_DMIC),
-       SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_ASUS_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_ASUS_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_ASUS_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_ASUS_AMIC),
+                     ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269VB_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269VB_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269VB_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269VB_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82Jv", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC),
+       SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC),
        SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
-                     ALC269_ASUS_DMIC),
+                     ALC269_DMIC),
        SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
-                     ALC269_ASUS_DMIC),
-       SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_ASUS_DMIC),
-       SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_ASUS_DMIC),
-       SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
+                     ALC269_DMIC),
+       SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC),
+       SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC),
+       SND_PCI_QUIRK(0x104d, 0x9071, "SONY XTB", ALC269_DMIC),
        SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
+       SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_DMIC),
+       SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
+       SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_AMIC),
+       SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_AMIC),
+       SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_DMIC),
+       SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_DMIC),
        {}
 };
 
@@ -13680,47 +13981,75 @@ static struct alc_config_preset alc269_presets[] = {
                .setup = alc269_quanta_fl1_setup,
                .init_hook = alc269_quanta_fl1_init_hook,
        },
-       [ALC269_ASUS_AMIC] = {
-               .mixers = { alc269_eeepc_mixer },
-               .cap_mixer = alc269_epc_capture_mixer,
+       [ALC269_AMIC] = {
+               .mixers = { alc269_laptop_mixer },
+               .cap_mixer = alc269_laptop_analog_capture_mixer,
                .init_verbs = { alc269_init_verbs,
-                               alc269_eeepc_amic_init_verbs },
+                               alc269_laptop_amic_init_verbs },
                .num_dacs = ARRAY_SIZE(alc269_dac_nids),
                .dac_nids = alc269_dac_nids,
                .hp_nid = 0x03,
                .num_channel_mode = ARRAY_SIZE(alc269_modes),
                .channel_mode = alc269_modes,
-               .unsol_event = alc269_eeepc_unsol_event,
-               .setup = alc269_eeepc_amic_setup,
-               .init_hook = alc269_eeepc_inithook,
+               .unsol_event = alc269_laptop_unsol_event,
+               .setup = alc269_laptop_amic_setup,
+               .init_hook = alc269_laptop_inithook,
        },
-       [ALC269_ASUS_DMIC] = {
-               .mixers = { alc269_eeepc_mixer },
-               .cap_mixer = alc269_epc_capture_mixer,
+       [ALC269_DMIC] = {
+               .mixers = { alc269_laptop_mixer },
+               .cap_mixer = alc269_laptop_digital_capture_mixer,
                .init_verbs = { alc269_init_verbs,
-                               alc269_eeepc_dmic_init_verbs },
+                               alc269_laptop_dmic_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc269_dac_nids),
+               .dac_nids = alc269_dac_nids,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc269_modes),
+               .channel_mode = alc269_modes,
+               .unsol_event = alc269_laptop_unsol_event,
+               .setup = alc269_laptop_dmic_setup,
+               .init_hook = alc269_laptop_inithook,
+       },
+       [ALC269VB_AMIC] = {
+               .mixers = { alc269vb_laptop_mixer },
+               .cap_mixer = alc269vb_laptop_analog_capture_mixer,
+               .init_verbs = { alc269vb_init_verbs,
+                               alc269vb_laptop_amic_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc269_dac_nids),
+               .dac_nids = alc269_dac_nids,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc269_modes),
+               .channel_mode = alc269_modes,
+               .unsol_event = alc269_laptop_unsol_event,
+               .setup = alc269_laptop_amic_setup,
+               .init_hook = alc269_laptop_inithook,
+       },
+       [ALC269VB_DMIC] = {
+               .mixers = { alc269vb_laptop_mixer },
+               .cap_mixer = alc269vb_laptop_digital_capture_mixer,
+               .init_verbs = { alc269vb_init_verbs,
+                               alc269vb_laptop_dmic_init_verbs },
                .num_dacs = ARRAY_SIZE(alc269_dac_nids),
                .dac_nids = alc269_dac_nids,
                .hp_nid = 0x03,
                .num_channel_mode = ARRAY_SIZE(alc269_modes),
                .channel_mode = alc269_modes,
-               .unsol_event = alc269_eeepc_unsol_event,
-               .setup = alc269_eeepc_dmic_setup,
-               .init_hook = alc269_eeepc_inithook,
+               .unsol_event = alc269_laptop_unsol_event,
+               .setup = alc269vb_laptop_dmic_setup,
+               .init_hook = alc269_laptop_inithook,
        },
        [ALC269_FUJITSU] = {
                .mixers = { alc269_fujitsu_mixer },
-               .cap_mixer = alc269_epc_capture_mixer,
+               .cap_mixer = alc269_laptop_digital_capture_mixer,
                .init_verbs = { alc269_init_verbs,
-                               alc269_eeepc_dmic_init_verbs },
+                               alc269_laptop_dmic_init_verbs },
                .num_dacs = ARRAY_SIZE(alc269_dac_nids),
                .dac_nids = alc269_dac_nids,
                .hp_nid = 0x03,
                .num_channel_mode = ARRAY_SIZE(alc269_modes),
                .channel_mode = alc269_modes,
-               .unsol_event = alc269_eeepc_unsol_event,
-               .setup = alc269_eeepc_dmic_setup,
-               .init_hook = alc269_eeepc_inithook,
+               .unsol_event = alc269_laptop_unsol_event,
+               .setup = alc269_laptop_dmic_setup,
+               .init_hook = alc269_laptop_inithook,
        },
        [ALC269_LIFEBOOK] = {
                .mixers = { alc269_lifebook_mixer },
@@ -13741,6 +14070,7 @@ 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)
@@ -13757,6 +14087,7 @@ static int patch_alc269(struct hda_codec *codec)
                        alc_free(codec);
                        return -ENOMEM;
                }
+               is_alc269vb = 1;
        }
 
        board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
@@ -13792,7 +14123,7 @@ static int patch_alc269(struct hda_codec *codec)
        if (board_config != ALC269_AUTO)
                setup_preset(codec, &alc269_presets[board_config]);
 
-       if (codec->subsystem_id == 0x17aa3bf8) {
+       if (board_config == ALC269_QUANTA_FL1) {
                /* Due to a hardware problem on Lenovo Ideadpad, we need to
                 * fix the sample rate of analog I/O to 44.1kHz
                 */
@@ -13805,9 +14136,16 @@ static int patch_alc269(struct hda_codec *codec)
        spec->stream_digital_playback = &alc269_pcm_digital_playback;
        spec->stream_digital_capture = &alc269_pcm_digital_capture;
 
-       spec->adc_nids = alc269_adc_nids;
-       spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
-       spec->capsrc_nids = alc269_capsrc_nids;
+       if (!is_alc269vb) {
+               spec->adc_nids = alc269_adc_nids;
+               spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
+               spec->capsrc_nids = alc269_capsrc_nids;
+       } else {
+               spec->adc_nids = alc269vb_adc_nids;
+               spec->num_adc_nids = ARRAY_SIZE(alc269vb_adc_nids);
+               spec->capsrc_nids = alc269vb_capsrc_nids;
+       }
+
        if (!spec->cap_mixer)
                set_capture_mixer(codec);
        set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
@@ -13821,7 +14159,6 @@ static int patch_alc269(struct hda_codec *codec)
        if (!spec->loopback.amplist)
                spec->loopback.amplist = alc269_loopbacks;
 #endif
-       codec->proc_widget_hook = print_realtek_coef;
 
        return 0;
 }
@@ -14684,7 +15021,7 @@ static int alc861_parse_auto_config(struct hda_codec *codec)
        spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
        set_capture_mixer(codec);
 
-       alc_ssid_check(codec, 0x0e, 0x0f, 0x0b);
+       alc_ssid_check(codec, 0x0e, 0x0f, 0x0b, 0);
 
        return 1;
 }
@@ -14939,13 +15276,16 @@ static int patch_alc861(struct hda_codec *codec)
        spec->vmaster_nid = 0x03;
 
        codec->patch_ops = alc_patch_ops;
-       if (board_config == ALC861_AUTO)
+       if (board_config == ALC861_AUTO) {
                spec->init_hook = alc861_auto_init;
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+               spec->power_hook = alc_power_eapd;
+#endif
+       }
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        if (!spec->loopback.amplist)
                spec->loopback.amplist = alc861_loopbacks;
 #endif
-       codec->proc_widget_hook = print_realtek_coef;
 
        return 0;
 }
@@ -15572,7 +15912,7 @@ static struct alc_config_preset alc861vd_presets[] = {
 static int alc861vd_auto_create_input_ctls(struct hda_codec *codec,
                                                const struct auto_pin_cfg *cfg)
 {
-       return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x22, 0);
+       return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x09, 0);
 }
 
 
@@ -15808,7 +16148,7 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec)
        if (err < 0)
                return err;
 
-       alc_ssid_check(codec, 0x15, 0x1b, 0x14);
+       alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
 
        return 1;
 }
@@ -15925,7 +16265,6 @@ static int patch_alc861vd(struct hda_codec *codec)
        if (!spec->loopback.amplist)
                spec->loopback.amplist = alc861vd_loopbacks;
 #endif
-       codec->proc_widget_hook = print_realtek_coef;
 
        return 0;
 }
@@ -16392,13 +16731,6 @@ static struct hda_verb alc662_init_verbs[] = {
        /* ADC: mute amp left and right */
        {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
        {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* Front mixer: unmute input/output amp left and right (volume = 0) */
-
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
 
        {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -16448,6 +16780,28 @@ static struct hda_verb alc662_init_verbs[] = {
        { }
 };
 
+static struct hda_verb alc663_init_verbs[] = {
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       { }
+};
+
+static struct hda_verb alc272_init_verbs[] = {
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       { }
+};
+
 static struct hda_verb alc662_sue_init_verbs[] = {
        {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
        {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
@@ -16467,61 +16821,6 @@ static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
        {}
 };
 
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static struct hda_verb alc662_auto_init_verbs[] = {
-       /*
-        * Unmute ADC and set the default input to mic-in
-        */
-       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-       /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
-        * mixer widget
-        * Note: PASD motherboards uses the Line In 2 as the input for front
-        * panel mic (mic 2)
-        */
-       /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-
-       /*
-        * Set up output mixers (0x0c - 0x0f)
-        */
-       /* set vol=0 to output mixers */
-       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
-       /* set up input amps for analog loopback */
-       /* Amp Indices: DAC = 0, mixer = 1 */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-
-       /* FIXME: use matrix-type input source selection */
-       /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
-       /* Input mixer */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       { }
-};
-
-/* additional verbs for ALC663 */
-static struct hda_verb alc663_auto_init_verbs[] = {
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       { }
-};
-
 static struct hda_verb alc663_m51va_init_verbs[] = {
        {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
        {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
@@ -17272,6 +17571,7 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1),
        SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
        SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
+       SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC663_ASUS_MODE1),
        SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
        SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
        SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
@@ -17307,6 +17607,7 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
        SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
        SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC663_ASUS_MODE1),
        SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1),
        SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1),
        SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
@@ -17334,6 +17635,7 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = {
        SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10),
        SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
                      ALC662_3ST_6ch_DIG),
+       SND_PCI_QUIRK(0x152d, 0x2304, "Quanta WH1", ALC663_ASUS_H13),
        SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
        SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA),
        SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
@@ -17952,15 +18254,23 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
        spec->num_mux_defs = 1;
        spec->input_mux = &spec->private_imux[0];
 
-       add_verb(spec, alc662_auto_init_verbs);
-       if (codec->vendor_id == 0x10ec0663)
-               add_verb(spec, alc663_auto_init_verbs);
+       add_verb(spec, alc662_init_verbs);
+       if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
+           codec->vendor_id == 0x10ec0665)
+               add_verb(spec, alc663_init_verbs);
+
+       if (codec->vendor_id == 0x10ec0272)
+               add_verb(spec, alc272_init_verbs);
 
        err = alc_auto_add_mic_boost(codec);
        if (err < 0)
                return err;
 
-       alc_ssid_check(codec, 0x15, 0x1b, 0x14);
+       if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
+           codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
+           alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0x21);
+       else
+           alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
 
        return 1;
 }
@@ -18046,11 +18356,20 @@ static int patch_alc662(struct hda_codec *codec)
 
        if (!spec->cap_mixer)
                set_capture_mixer(codec);
-       if (codec->vendor_id == 0x10ec0662)
+
+       switch (codec->vendor_id) {
+       case 0x10ec0662:
                set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
-       else
+               break;
+       case 0x10ec0272:
+       case 0x10ec0663:
+       case 0x10ec0665:
                set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
-
+               break;
+       case 0x10ec0273:
+               set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
+               break;
+       }
        spec->vmaster_nid = 0x02;
 
        codec->patch_ops = alc_patch_ops;
@@ -18060,7 +18379,6 @@ static int patch_alc662(struct hda_codec *codec)
        if (!spec->loopback.amplist)
                spec->loopback.amplist = alc662_loopbacks;
 #endif
-       codec->proc_widget_hook = print_realtek_coef;
 
        return 0;
 }
@@ -18101,6 +18419,8 @@ static struct hda_codec_preset snd_hda_preset_realtek[] = {
        { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
          .patch = patch_alc662 },
        { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
+       { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 },
+       { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
        { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
        { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
        { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
index 43b436c5d01bc245a3bbbdfcd6c54f08af0feaa3..f419ee8d75f0fe0b351c26c396cb19adce748de3 100644 (file)
@@ -122,6 +122,7 @@ static int si3054_switch_put(struct snd_kcontrol *kcontrol,
 #define SI3054_KCONTROL(kname,reg,mask) { \
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
        .name = kname, \
+       .subdevice = HDA_SUBDEV_NID_FLAG | reg, \
        .info = si3054_switch_info, \
        .get  = si3054_switch_get, \
        .put  = si3054_switch_put, \
index 799ba2570902a066ead90e38a1ce17e5b351f4e8..8c416bb18a57cef781249611bdbae060212b924d 100644 (file)
@@ -568,6 +568,11 @@ static hda_nid_t stac92hd83xxx_pin_nids[10] = {
        0x0f, 0x10, 0x11, 0x1f, 0x20,
 };
 
+static hda_nid_t stac92hd88xxx_pin_nids[10] = {
+       0x0a, 0x0b, 0x0c, 0x0d,
+       0x0f, 0x11, 0x1f, 0x20,
+};
+
 #define STAC92HD71BXX_NUM_PINS 13
 static hda_nid_t stac92hd71bxx_pin_nids_4port[STAC92HD71BXX_NUM_PINS] = {
        0x0a, 0x0b, 0x0c, 0x0d, 0x00,
@@ -2688,7 +2693,7 @@ static struct snd_kcontrol_new *
 stac_control_new(struct sigmatel_spec *spec,
                 struct snd_kcontrol_new *ktemp,
                 const char *name,
-                hda_nid_t nid)
+                unsigned int subdev)
 {
        struct snd_kcontrol_new *knew;
 
@@ -2704,8 +2709,7 @@ stac_control_new(struct sigmatel_spec *spec,
                spec->kctls.alloced--;
                return NULL;
        }
-       if (nid)
-               knew->subdevice = HDA_SUBDEV_NID_FLAG | nid;
+       knew->subdevice = subdev;
        return knew;
 }
 
@@ -2715,7 +2719,7 @@ static int stac92xx_add_control_temp(struct sigmatel_spec *spec,
                                     unsigned long val)
 {
        struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name,
-                                                        get_amp_nid_(val));
+                                                        HDA_SUBDEV_AMP_FLAG);
        if (!knew)
                return -ENOMEM;
        knew->index = idx;
@@ -2874,6 +2878,13 @@ static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid)
 
        conn_len = snd_hda_get_connections(codec, nid, conn,
                                           HDA_MAX_CONNECTIONS);
+       /* 92HD88: trace back up the link of nids to find the DAC */
+       while (conn_len == 1 && (get_wcaps_type(get_wcaps(codec, conn[0]))
+                                       != AC_WID_AUD_OUT)) {
+               nid = conn[0];
+               conn_len = snd_hda_get_connections(codec, nid, conn,
+                       HDA_MAX_CONNECTIONS);
+       }
        for (j = 0; j < conn_len; j++) {
                wcaps = get_wcaps(codec, conn[j]);
                wtype = get_wcaps_type(wcaps);
@@ -4160,34 +4171,52 @@ static void stac92xx_power_down(struct hda_codec *codec)
 static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid,
                                  int enable);
 
+static inline int get_int_hint(struct hda_codec *codec, const char *key,
+                              int *valp)
+{
+       const char *p;
+       p = snd_hda_get_hint(codec, key);
+       if (p) {
+               unsigned long val;
+               if (!strict_strtoul(p, 0, &val)) {
+                       *valp = val;
+                       return 1;
+               }
+       }
+       return 0;
+}
+
 /* override some hints from the hwdep entry */
 static void stac_store_hints(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
-       const char *p;
        int val;
 
        val = snd_hda_get_bool_hint(codec, "hp_detect");
        if (val >= 0)
                spec->hp_detect = val;
-       p = snd_hda_get_hint(codec, "gpio_mask");
-       if (p) {
-               spec->gpio_mask = simple_strtoul(p, NULL, 0);
+       if (get_int_hint(codec, "gpio_mask", &spec->gpio_mask)) {
                spec->eapd_mask = spec->gpio_dir = spec->gpio_data =
                        spec->gpio_mask;
        }
-       p = snd_hda_get_hint(codec, "gpio_dir");
-       if (p)
-               spec->gpio_dir = simple_strtoul(p, NULL, 0) & spec->gpio_mask;
-       p = snd_hda_get_hint(codec, "gpio_data");
-       if (p)
-               spec->gpio_data = simple_strtoul(p, NULL, 0) & spec->gpio_mask;
-       p = snd_hda_get_hint(codec, "eapd_mask");
-       if (p)
-               spec->eapd_mask = simple_strtoul(p, NULL, 0) & spec->gpio_mask;
+       if (get_int_hint(codec, "gpio_dir", &spec->gpio_dir))
+               spec->gpio_mask &= spec->gpio_mask;
+       if (get_int_hint(codec, "gpio_data", &spec->gpio_data))
+               spec->gpio_dir &= spec->gpio_mask;
+       if (get_int_hint(codec, "eapd_mask", &spec->eapd_mask))
+               spec->eapd_mask &= spec->gpio_mask;
+       if (get_int_hint(codec, "gpio_mute", &spec->gpio_mute))
+               spec->gpio_mute &= spec->gpio_mask;
        val = snd_hda_get_bool_hint(codec, "eapd_switch");
        if (val >= 0)
                spec->eapd_switch = val;
+       get_int_hint(codec, "gpio_led_polarity", &spec->gpio_led_polarity);
+       if (get_int_hint(codec, "gpio_led", &spec->gpio_led)) {
+               spec->gpio_mask |= spec->gpio_led;
+               spec->gpio_dir |= spec->gpio_led;
+               if (spec->gpio_led_polarity)
+                       spec->gpio_data |= spec->gpio_led;
+       }
 }
 
 static int stac92xx_init(struct hda_codec *codec)
@@ -4334,6 +4363,12 @@ static int stac92xx_init(struct hda_codec *codec)
                if (enable_pin_detect(codec, nid, STAC_PWR_EVENT))
                        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->dac_list)
                stac92xx_power_down(codec);
        return 0;
@@ -4372,18 +4407,8 @@ static void stac92xx_free_kctls(struct hda_codec *codec)
 static void stac92xx_shutup(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
-       int i;
-       hda_nid_t nid;
 
-       /* reset each pin before powering down DAC/ADC to avoid click noise */
-       nid = codec->start_nid;
-       for (i = 0; i < codec->num_nodes; i++, nid++) {
-               unsigned int wcaps = get_wcaps(codec, nid);
-               unsigned int wid_type = get_wcaps_type(wcaps);
-               if (wid_type == AC_WID_PIN)
-                       snd_hda_codec_read(codec, nid, 0,
-                               AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
-       }
+       snd_hda_shutup_pins(codec);
 
        if (spec->eapd_mask)
                stac_gpio_set(codec, spec->gpio_mask,
@@ -4735,19 +4760,14 @@ static int hp_blike_system(u32 subsystem_id);
 static void set_hp_led_gpio(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
-       switch (codec->vendor_id) {
-       case 0x111d7608:
-               /* GPIO 0 */
-               spec->gpio_led = 0x01;
-               break;
-       case 0x111d7600:
-       case 0x111d7601:
-       case 0x111d7602:
-       case 0x111d7603:
-               /* GPIO 3 */
-               spec->gpio_led = 0x08;
-               break;
-       }
+       unsigned int gpio;
+
+       gpio = snd_hda_param_read(codec, codec->afg, AC_PAR_GPIO_CAP);
+       gpio &= AC_GPIO_IO_COUNT;
+       if (gpio > 3)
+               spec->gpio_led = 0x08; /* GPIO 3 */
+       else
+               spec->gpio_led = 0x01; /* GPIO 0 */
 }
 
 /*
@@ -4770,7 +4790,7 @@ static void set_hp_led_gpio(struct hda_codec *codec)
  * Need more information on whether it is true across the entire series.
  * -- kunal
  */
-static int find_mute_led_gpio(struct hda_codec *codec)
+static int find_mute_led_gpio(struct hda_codec *codec, int default_polarity)
 {
        struct sigmatel_spec *spec = codec->spec;
        const struct dmi_device *dev = NULL;
@@ -4797,7 +4817,7 @@ static int find_mute_led_gpio(struct hda_codec *codec)
                 */
                if (!hp_blike_system(codec->subsystem_id)) {
                        set_hp_led_gpio(codec);
-                       spec->gpio_led_polarity = 1;
+                       spec->gpio_led_polarity = default_polarity;
                        return 1;
                }
        }
@@ -4895,6 +4915,11 @@ 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 
        return 0;
 }
 
@@ -4914,43 +4939,29 @@ static int stac92xx_hp_check_power_status(struct hda_codec *codec,
                                              hda_nid_t nid)
 {
        struct sigmatel_spec *spec = codec->spec;
+       int i, muted = 1;
 
-       if (nid == 0x10) {
-               if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) &
-                   HDA_AMP_MUTE)
-                       spec->gpio_data &= ~spec->gpio_led; /* orange */
-               else
-                       spec->gpio_data |= spec->gpio_led; /* white */
-
-               if (!spec->gpio_led_polarity) {
-                       /* LED state is inverted on these systems */
-                       spec->gpio_data ^= spec->gpio_led;
+       for (i = 0; i < spec->multiout.num_dacs; i++) {
+               nid = spec->multiout.dac_nids[i];
+               if (!(snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) &
+                     HDA_AMP_MUTE)) {
+                       muted = 0; /* something heard */
+                       break;
                }
-
-               stac_gpio_set(codec, spec->gpio_mask,
-                             spec->gpio_dir,
-                             spec->gpio_data);
        }
+       if (muted)
+               spec->gpio_data &= ~spec->gpio_led; /* orange */
+       else
+               spec->gpio_data |= spec->gpio_led; /* white */
 
-       return 0;
-}
-
-static int idt92hd83xxx_hp_check_power_status(struct hda_codec *codec,
-                                             hda_nid_t nid)
-{
-       struct sigmatel_spec *spec = codec->spec;
+       if (!spec->gpio_led_polarity) {
+               /* LED state is inverted on these systems */
+               spec->gpio_data ^= spec->gpio_led;
+       }
 
-       if (nid != 0x13)
-               return 0;
-       if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) & HDA_AMP_MUTE)
-               spec->gpio_data |= spec->gpio_led; /* mute LED on */
-       else
-               spec->gpio_data &= ~spec->gpio_led; /* mute LED off */
        stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data);
-
        return 0;
 }
-
 #endif
 
 static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state)
@@ -5272,7 +5283,6 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
        hda_nid_t conn[STAC92HD83_DAC_COUNT + 1];
        int err;
        int num_dacs;
-       hda_nid_t nid;
 
        spec  = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
@@ -5311,7 +5321,18 @@ again:
                                stac92hd83xxx_brd_tbl[spec->board_config]);
 
        switch (codec->vendor_id) {
+       case 0x111d7666:
+       case 0x111d7667:
+       case 0x111d7668:
+       case 0x111d7669:
+               spec->num_pins = ARRAY_SIZE(stac92hd88xxx_pin_nids);
+               spec->pin_nids = stac92hd88xxx_pin_nids;
+               spec->mono_nid = 0;
+               spec->digbeep_nid = 0;
+               spec->num_pwrs = 0;
+               break;
        case 0x111d7604:
+       case 0x111d76d4:
        case 0x111d7605:
        case 0x111d76d5:
                if (spec->board_config == STAC_92HD83XXX_PWR_REF)
@@ -5322,8 +5343,10 @@ again:
 
        codec->patch_ops = stac92xx_patch_ops;
 
-       if (spec->board_config == STAC_92HD83XXX_HP)
-               spec->gpio_led = 0x01;
+       if (find_mute_led_gpio(codec, 0))
+               snd_printd("mute LED gpio %d polarity %d\n",
+                               spec->gpio_led,
+                               spec->gpio_led_polarity);
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        if (spec->gpio_led) {
@@ -5332,7 +5355,7 @@ again:
                spec->gpio_data |= spec->gpio_led;
                /* register check_power_status callback. */
                codec->patch_ops.check_power_status =
-                       idt92hd83xxx_hp_check_power_status;
+                       stac92xx_hp_check_power_status;
        }
 #endif 
 
@@ -5352,24 +5375,21 @@ again:
                return err;
        }
 
-       switch (spec->board_config) {
-       case STAC_DELL_S14:
-               nid = 0xf;
-               break;
-       default:
-               nid = 0xe;
-               break;
-       }
-
-       num_dacs = snd_hda_get_connections(codec, nid,
+       /* docking output support */
+       num_dacs = snd_hda_get_connections(codec, 0xF,
                                conn, STAC92HD83_DAC_COUNT + 1) - 1;
-       if (num_dacs < 0)
-               num_dacs = STAC92HD83_DAC_COUNT;
-
-       /* set port X to select the last DAC
-        */
-       snd_hda_codec_write_cache(codec, nid, 0,
+       /* skip non-DAC connections */
+       while (num_dacs >= 0 &&
+                       (get_wcaps_type(get_wcaps(codec, conn[num_dacs]))
+                                       != AC_WID_AUD_OUT))
+               num_dacs--;
+       /* set port E and F to select the last DAC */
+       if (num_dacs >= 0) {
+               snd_hda_codec_write_cache(codec, 0xE, 0,
+                       AC_VERB_SET_CONNECT_SEL, num_dacs);
+               snd_hda_codec_write_cache(codec, 0xF, 0,
                        AC_VERB_SET_CONNECT_SEL, num_dacs);
+       }
 
        codec->proc_widget_hook = stac92hd_proc_hook;
 
@@ -5431,6 +5451,54 @@ static int stac92hd71bxx_connected_smuxes(struct hda_codec *codec,
                return 0;
 }
 
+/* HP dv7 bass switch - GPIO5 */
+#define stac_hp_bass_gpio_info snd_ctl_boolean_mono_info
+static int stac_hp_bass_gpio_get(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct sigmatel_spec *spec = codec->spec;
+       ucontrol->value.integer.value[0] = !!(spec->gpio_data & 0x20);
+       return 0;
+}
+
+static int stac_hp_bass_gpio_put(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct sigmatel_spec *spec = codec->spec;
+       unsigned int gpio_data;
+
+       gpio_data = (spec->gpio_data & ~0x20) |
+               (ucontrol->value.integer.value[0] ? 0x20 : 0);
+       if (gpio_data == spec->gpio_data)
+               return 0;
+       spec->gpio_data = gpio_data;
+       stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data);
+       return 1;
+}
+
+static struct snd_kcontrol_new stac_hp_bass_sw_ctrl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .info = stac_hp_bass_gpio_info,
+       .get = stac_hp_bass_gpio_get,
+       .put = stac_hp_bass_gpio_put,
+};
+
+static int stac_add_hp_bass_switch(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (!stac_control_new(spec, &stac_hp_bass_sw_ctrl,
+                             "Bass Speaker Playback Switch", 0))
+               return -ENOMEM;
+
+       spec->gpio_mask |= 0x20;
+       spec->gpio_dir |= 0x20;
+       spec->gpio_data |= 0x20;
+       return 0;
+}
+
 static int patch_stac92hd71bxx(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec;
@@ -5602,7 +5670,6 @@ again:
                 */
                spec->num_smuxes = 1;
                spec->num_dmuxes = 1;
-               spec->gpio_led = 0x01;
                /* fallthrough */
        case STAC_HP_DV5:
                snd_hda_codec_set_pincfg(codec, 0x0d, 0x90170010);
@@ -5617,8 +5684,6 @@ again:
                spec->num_dmics = 1;
                spec->num_dmuxes = 1;
                spec->num_smuxes = 1;
-               /* orange/white mute led on GPIO3, orange=0, white=1 */
-               spec->gpio_led = 0x08;
                break;
        }
 
@@ -5640,7 +5705,7 @@ again:
                }
        }
 
-       if (find_mute_led_gpio(codec))
+       if (find_mute_led_gpio(codec, 1))
                snd_printd("mute LED gpio %d polarity %d\n",
                                spec->gpio_led,
                                spec->gpio_led_polarity);
@@ -5674,6 +5739,15 @@ again:
                return err;
        }
 
+       /* enable bass on HP dv7 */
+       if (spec->board_config == STAC_HP_DV5) {
+               unsigned int cap;
+               cap = snd_hda_param_read(codec, 0x1, AC_PAR_GPIO_CAP);
+               cap &= AC_GPIO_IO_COUNT;
+               if (cap >= 6)
+                       stac_add_hp_bass_switch(codec);
+       }
+
        codec->proc_widget_hook = stac92hd7x_proc_hook;
 
        return 0;
@@ -6172,8 +6246,13 @@ static struct hda_codec_preset snd_hda_preset_sigmatel[] = {
        { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
        { .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx},
        { .id = 0x111d7604, .name = "92HD83C1X5", .patch = patch_stac92hd83xxx},
+       { .id = 0x111d76d4, .name = "92HD83C1C5", .patch = patch_stac92hd83xxx},
        { .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx},
        { .id = 0x111d76d5, .name = "92HD81B1C5", .patch = patch_stac92hd83xxx},
+       { .id = 0x111d7666, .name = "92HD88B3", .patch = patch_stac92hd83xxx},
+       { .id = 0x111d7667, .name = "92HD88B1", .patch = patch_stac92hd83xxx},
+       { .id = 0x111d7668, .name = "92HD88B2", .patch = patch_stac92hd83xxx},
+       { .id = 0x111d7669, .name = "92HD88B4", .patch = patch_stac92hd83xxx},
        { .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx},
        { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
        { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
index b70e26ad263f19c9b21e605274febb63d2a29d10..9ddc37300f6b5cd88420ff885823e486e0cd3dd5 100644 (file)
@@ -54,6 +54,8 @@
 #include "hda_codec.h"
 #include "hda_local.h"
 
+#define NID_MAPPING            (-1)
+
 /* amp values */
 #define AMP_VAL_IDX_SHIFT      19
 #define AMP_VAL_IDX_MASK       (0x0f<<19)
@@ -157,6 +159,19 @@ struct via_spec {
 #endif
 };
 
+static struct via_spec * via_new_spec(struct hda_codec *codec)
+{
+       struct via_spec *spec;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return NULL;
+
+       codec->spec = spec;
+       spec->codec = codec;
+       return spec;
+}
+
 static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec)
 {
        u32 vendor_id = codec->vendor_id;
@@ -443,11 +458,27 @@ static int via_add_control(struct via_spec *spec, int type, const char *name,
        if (!knew->name)
                return -ENOMEM;
        if (get_amp_nid_(val))
-               knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val);
+               knew->subdevice = HDA_SUBDEV_AMP_FLAG;
        knew->private_value = val;
        return 0;
 }
 
+static struct snd_kcontrol_new *via_clone_control(struct via_spec *spec,
+                                               struct snd_kcontrol_new *tmpl)
+{
+       struct snd_kcontrol_new *knew;
+
+       snd_array_init(&spec->kctls, sizeof(*knew), 32);
+       knew = snd_array_new(&spec->kctls);
+       if (!knew)
+               return NULL;
+       *knew = *tmpl;
+       knew->name = kstrdup(tmpl->name, GFP_KERNEL);
+       if (!knew->name)
+               return NULL;
+       return 0;
+}
+
 static void via_free_kctls(struct hda_codec *codec)
 {
        struct via_spec *spec = codec->spec;
@@ -1088,24 +1119,9 @@ static int via_independent_hp_get(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct via_spec *spec = codec->spec;
-       hda_nid_t nid;
+       hda_nid_t nid = kcontrol->private_value;
        unsigned int pinsel;
 
-       switch (spec->codec_type) {
-       case VT1718S:
-               nid = 0x34;
-               break;
-       case VT2002P:
-               nid = 0x35;
-               break;
-       case VT1812:
-               nid = 0x3d;
-               break;
-       default:
-               nid = spec->autocfg.hp_pins[0];
-               break;
-       }
        /* use !! to translate conn sel 2 for VT1718S */
        pinsel = !!snd_hda_codec_read(codec, nid, 0,
                                      AC_VERB_GET_CONNECT_SEL,
@@ -1127,29 +1143,24 @@ static void activate_ctl(struct hda_codec *codec, const char *name, int active)
        }
 }
 
+static hda_nid_t side_mute_channel(struct via_spec *spec)
+{
+       switch (spec->codec_type) {
+       case VT1708:            return 0x1b;
+       case VT1709_10CH:       return 0x29;
+       case VT1708B_8CH:       /* fall thru */
+       case VT1708S:           return 0x27;
+       default:                return 0;
+       }
+}
+
 static int update_side_mute_status(struct hda_codec *codec)
 {
        /* mute side channel */
        struct via_spec *spec = codec->spec;
        unsigned int parm = spec->hp_independent_mode
                ? AMP_OUT_MUTE : AMP_OUT_UNMUTE;
-       hda_nid_t sw3;
-
-       switch (spec->codec_type) {
-       case VT1708:
-               sw3 = 0x1b;
-               break;
-       case VT1709_10CH:
-               sw3 = 0x29;
-               break;
-       case VT1708B_8CH:
-       case VT1708S:
-               sw3 = 0x27;
-               break;
-       default:
-               sw3 = 0;
-               break;
-       }
+       hda_nid_t sw3 = side_mute_channel(spec);
 
        if (sw3)
                snd_hda_codec_write(codec, sw3, 0, AC_VERB_SET_AMP_GAIN_MUTE,
@@ -1162,28 +1173,11 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct via_spec *spec = codec->spec;
-       hda_nid_t nid = spec->autocfg.hp_pins[0];
+       hda_nid_t nid = kcontrol->private_value;
        unsigned int pinsel = ucontrol->value.enumerated.item[0];
        /* Get Independent Mode index of headphone pin widget */
        spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel
                ? 1 : 0;
-
-       switch (spec->codec_type) {
-       case VT1718S:
-               nid = 0x34;
-               pinsel = pinsel ? 2 : 0; /* indep HP use AOW4 (index 2) */
-               spec->multiout.num_dacs = 4;
-               break;
-       case VT2002P:
-               nid = 0x35;
-               break;
-       case VT1812:
-               nid = 0x3d;
-               break;
-       default:
-               nid = spec->autocfg.hp_pins[0];
-               break;
-       }
        snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, pinsel);
 
        if (spec->multiout.hp_nid && spec->multiout.hp_nid
@@ -1207,18 +1201,55 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
-static struct snd_kcontrol_new via_hp_mixer[] = {
+static struct snd_kcontrol_new via_hp_mixer[2] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Independent HP",
-               .count = 1,
                .info = via_independent_hp_info,
                .get = via_independent_hp_get,
                .put = via_independent_hp_put,
        },
-       { } /* end */
+       {
+               .iface = NID_MAPPING,
+               .name = "Independent HP",
+       },
 };
 
+static int via_hp_build(struct via_spec *spec)
+{
+       struct snd_kcontrol_new *knew;
+       hda_nid_t nid;
+
+       knew = via_clone_control(spec, &via_hp_mixer[0]);
+       if (knew == NULL)
+               return -ENOMEM;
+
+       switch (spec->codec_type) {
+       case VT1718S:
+               nid = 0x34;
+               break;
+       case VT2002P:
+               nid = 0x35;
+               break;
+       case VT1812:
+               nid = 0x3d;
+               break;
+       default:
+               nid = spec->autocfg.hp_pins[0];
+               break;
+       }
+
+       knew->subdevice = HDA_SUBDEV_NID_FLAG | nid;
+       knew->private_value = nid;
+
+       knew = via_clone_control(spec, &via_hp_mixer[1]);
+       if (knew == NULL)
+               return -ENOMEM;
+       knew->subdevice = side_mute_channel(spec);
+
+       return 0;
+}
+
 static void notify_aa_path_ctls(struct hda_codec *codec)
 {
        int i;
@@ -1376,7 +1407,7 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol,
        return 1;
 }
 
-static struct snd_kcontrol_new via_smart51_mixer[] = {
+static struct snd_kcontrol_new via_smart51_mixer[2] = {
        {
         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
         .name = "Smart 5.1",
@@ -1385,9 +1416,36 @@ static struct snd_kcontrol_new via_smart51_mixer[] = {
         .get = via_smart51_get,
         .put = via_smart51_put,
         },
-       {}                      /* end */
+       {
+        .iface = NID_MAPPING,
+        .name = "Smart 5.1",
+       }
 };
 
+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 };
+       hda_nid_t nid;
+       int i;
+
+       knew = via_clone_control(spec, &via_smart51_mixer[0]);
+       if (knew == NULL)
+               return -ENOMEM;
+
+       for (i = 0; i < ARRAY_SIZE(index); i++) {
+               nid = spec->autocfg.input_pins[index[i]];
+               if (nid) {
+                       knew = via_clone_control(spec, &via_smart51_mixer[1]);
+                       if (knew == NULL)
+                               return -ENOMEM;
+                       knew->subdevice = nid;
+               }
+       }
+
+       return 0;
+}
+
 /* capture mixer elements */
 static struct snd_kcontrol_new vt1708_capture_mixer[] = {
        HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
@@ -1819,8 +1877,9 @@ static struct hda_pcm_stream vt1708_pcm_digital_capture = {
 static int via_build_controls(struct hda_codec *codec)
 {
        struct via_spec *spec = codec->spec;
-       int err;
-       int i;
+       struct snd_kcontrol *kctl;
+       struct snd_kcontrol_new *knew;
+       int err, i;
 
        for (i = 0; i < spec->num_mixers; i++) {
                err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
@@ -1845,6 +1904,27 @@ static int via_build_controls(struct hda_codec *codec)
                        return err;
        }
 
+       /* assign Capture Source enums to NID */
+       kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
+       for (i = 0; kctl && i < kctl->count; i++) {
+               err = snd_hda_add_nid(codec, kctl, i, spec->mux_nids[i]);
+               if (err < 0)
+                       return err;
+       }
+
+       /* other nid->control mapping */
+       for (i = 0; i < spec->num_mixers; i++) {
+               for (knew = spec->mixers[i]; knew->name; knew++) {
+                       if (knew->iface != NID_MAPPING)
+                               continue;
+                       kctl = snd_hda_find_mixer_ctl(codec, knew->name);
+                       if (kctl == NULL)
+                               continue;
+                       err = snd_hda_add_nid(codec, kctl, 0,
+                                             knew->subdevice);
+               }
+       }
+
        /* init power states */
        set_jack_power_state(codec);
        analog_low_current_mode(codec, 1);
@@ -2481,9 +2561,9 @@ static int vt1708_parse_auto_config(struct hda_codec *codec)
        spec->input_mux = &spec->private_imux[0];
 
        if (spec->hp_mux)
-               spec->mixers[spec->num_mixers++] = via_hp_mixer;
+               via_hp_build(spec);
 
-       spec->mixers[spec->num_mixers++] = via_smart51_mixer;
+       via_smart51_build(spec);
        return 1;
 }
 
@@ -2554,12 +2634,10 @@ static int patch_vt1708(struct hda_codec *codec)
        int err;
 
        /* create a codec specific record */
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       spec = via_new_spec(codec);
        if (spec == NULL)
                return -ENOMEM;
 
-       codec->spec = spec;
-
        /* automatic parse from the BIOS config */
        err = vt1708_parse_auto_config(codec);
        if (err < 0) {
@@ -2597,7 +2675,6 @@ static int patch_vt1708(struct hda_codec *codec)
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        spec->loopback.amplist = vt1708_loopbacks;
 #endif
-       spec->codec = codec;
        INIT_DELAYED_WORK(&spec->vt1708_hp_work, vt1708_update_hp_jack_state);
        return 0;
 }
@@ -3010,9 +3087,9 @@ static int vt1709_parse_auto_config(struct hda_codec *codec)
        spec->input_mux = &spec->private_imux[0];
 
        if (spec->hp_mux)
-               spec->mixers[spec->num_mixers++] = via_hp_mixer;
+               via_hp_build(spec);
 
-       spec->mixers[spec->num_mixers++] = via_smart51_mixer;
+       via_smart51_build(spec);
        return 1;
 }
 
@@ -3032,12 +3109,10 @@ static int patch_vt1709_10ch(struct hda_codec *codec)
        int err;
 
        /* create a codec specific record */
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       spec = via_new_spec(codec);
        if (spec == NULL)
                return -ENOMEM;
 
-       codec->spec = spec;
-
        err = vt1709_parse_auto_config(codec);
        if (err < 0) {
                via_free(codec);
@@ -3126,12 +3201,10 @@ static int patch_vt1709_6ch(struct hda_codec *codec)
        int err;
 
        /* create a codec specific record */
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       spec = via_new_spec(codec);
        if (spec == NULL)
                return -ENOMEM;
 
-       codec->spec = spec;
-
        err = vt1709_parse_auto_config(codec);
        if (err < 0) {
                via_free(codec);
@@ -3581,9 +3654,9 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec)
        spec->input_mux = &spec->private_imux[0];
 
        if (spec->hp_mux)
-               spec->mixers[spec->num_mixers++] = via_hp_mixer;
+               via_hp_build(spec);
 
-       spec->mixers[spec->num_mixers++] = via_smart51_mixer;
+       via_smart51_build(spec);
        return 1;
 }
 
@@ -3605,12 +3678,10 @@ static int patch_vt1708B_8ch(struct hda_codec *codec)
        if (get_codec_type(codec) == VT1708BCE)
                return patch_vt1708S(codec);
        /* create a codec specific record */
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       spec = via_new_spec(codec);
        if (spec == NULL)
                return -ENOMEM;
 
-       codec->spec = spec;
-
        /* automatic parse from the BIOS config */
        err = vt1708B_parse_auto_config(codec);
        if (err < 0) {
@@ -3657,12 +3728,10 @@ static int patch_vt1708B_4ch(struct hda_codec *codec)
        int err;
 
        /* create a codec specific record */
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       spec = via_new_spec(codec);
        if (spec == NULL)
                return -ENOMEM;
 
-       codec->spec = spec;
-
        /* automatic parse from the BIOS config */
        err = vt1708B_parse_auto_config(codec);
        if (err < 0) {
@@ -4071,9 +4140,9 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec)
        spec->input_mux = &spec->private_imux[0];
 
        if (spec->hp_mux)
-               spec->mixers[spec->num_mixers++] = via_hp_mixer;
+               via_hp_build(spec);
 
-       spec->mixers[spec->num_mixers++] = via_smart51_mixer;
+       via_smart51_build(spec);
        return 1;
 }
 
@@ -4103,12 +4172,10 @@ static int patch_vt1708S(struct hda_codec *codec)
        int err;
 
        /* create a codec specific record */
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       spec = via_new_spec(codec);
        if (spec == NULL)
                return -ENOMEM;
 
-       codec->spec = spec;
-
        /* automatic parse from the BIOS config */
        err = vt1708S_parse_auto_config(codec);
        if (err < 0) {
@@ -4443,7 +4510,7 @@ static int vt1702_parse_auto_config(struct hda_codec *codec)
        spec->input_mux = &spec->private_imux[0];
 
        if (spec->hp_mux)
-               spec->mixers[spec->num_mixers++] = via_hp_mixer;
+               via_hp_build(spec);
 
        return 1;
 }
@@ -4464,12 +4531,10 @@ static int patch_vt1702(struct hda_codec *codec)
        int err;
 
        /* create a codec specific record */
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       spec = via_new_spec(codec);
        if (spec == NULL)
                return -ENOMEM;
 
-       codec->spec = spec;
-
        /* automatic parse from the BIOS config */
        err = vt1702_parse_auto_config(codec);
        if (err < 0) {
@@ -4865,9 +4930,9 @@ static int vt1718S_parse_auto_config(struct hda_codec *codec)
        spec->input_mux = &spec->private_imux[0];
 
        if (spec->hp_mux)
-               spec->mixers[spec->num_mixers++] = via_hp_mixer;
+               via_hp_build(spec);
 
-       spec->mixers[spec->num_mixers++] = via_smart51_mixer;
+       via_smart51_build(spec);
 
        return 1;
 }
@@ -4888,12 +4953,10 @@ static int patch_vt1718S(struct hda_codec *codec)
        int err;
 
        /* create a codec specific record */
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       spec = via_new_spec(codec);
        if (spec == NULL)
                return -ENOMEM;
 
-       codec->spec = spec;
-
        /* automatic parse from the BIOS config */
        err = vt1718S_parse_auto_config(codec);
        if (err < 0) {
@@ -5014,6 +5077,7 @@ static struct snd_kcontrol_new vt1716s_dmic_mixer[] = {
        {
         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
         .name = "Digital Mic Capture Switch",
+        .subdevice = HDA_SUBDEV_NID_FLAG | 0x26,
         .count = 1,
         .info = vt1716s_dmic_info,
         .get = vt1716s_dmic_get,
@@ -5361,9 +5425,9 @@ static int vt1716S_parse_auto_config(struct hda_codec *codec)
        spec->input_mux = &spec->private_imux[0];
 
        if (spec->hp_mux)
-               spec->mixers[spec->num_mixers++] = via_hp_mixer;
+               via_hp_build(spec);
 
-       spec->mixers[spec->num_mixers++] = via_smart51_mixer;
+       via_smart51_build(spec);
 
        return 1;
 }
@@ -5384,12 +5448,10 @@ static int patch_vt1716S(struct hda_codec *codec)
        int err;
 
        /* create a codec specific record */
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       spec = via_new_spec(codec);
        if (spec == NULL)
                return -ENOMEM;
 
-       codec->spec = spec;
-
        /* automatic parse from the BIOS config */
        err = vt1716S_parse_auto_config(codec);
        if (err < 0) {
@@ -5719,7 +5781,7 @@ static int vt2002P_parse_auto_config(struct hda_codec *codec)
        spec->input_mux = &spec->private_imux[0];
 
        if (spec->hp_mux)
-               spec->mixers[spec->num_mixers++] = via_hp_mixer;
+               via_hp_build(spec);
 
        return 1;
 }
@@ -5741,12 +5803,10 @@ static int patch_vt2002P(struct hda_codec *codec)
        int err;
 
        /* create a codec specific record */
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       spec = via_new_spec(codec);
        if (spec == NULL)
                return -ENOMEM;
 
-       codec->spec = spec;
-
        /* automatic parse from the BIOS config */
        err = vt2002P_parse_auto_config(codec);
        if (err < 0) {
@@ -6070,7 +6130,7 @@ static int vt1812_parse_auto_config(struct hda_codec *codec)
        spec->input_mux = &spec->private_imux[0];
 
        if (spec->hp_mux)
-               spec->mixers[spec->num_mixers++] = via_hp_mixer;
+               via_hp_build(spec);
 
        return 1;
 }
@@ -6092,12 +6152,10 @@ static int patch_vt1812(struct hda_codec *codec)
        int err;
 
        /* create a codec specific record */
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       spec = via_new_spec(codec);
        if (spec == NULL)
                return -ENOMEM;
 
-       codec->spec = spec;
-
        /* automatic parse from the BIOS config */
        err = vt1812_parse_auto_config(codec);
        if (err < 0) {
index c7cff6f8168a2d0159a0df20ea2c97550dafd6db..4fc6d8bc637e1f4498a900b81f8e958c2e8938a1 100644 (file)
@@ -106,7 +106,7 @@ module_param_array(dxr_enable, int, NULL, 0444);
 MODULE_PARM_DESC(dxr_enable, "Enable DXR support for Terratec DMX6FIRE.");
 
 
-static const struct pci_device_id snd_ice1712_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_ice1712_ids) = {
        { PCI_VDEVICE(ICE, PCI_DEVICE_ID_ICE_1712), 0 },   /* ICE1712 */
        { 0, }
 };
@@ -1180,6 +1180,10 @@ static int snd_ice1712_playback_pro_open(struct snd_pcm_substream *substream)
        snd_pcm_set_sync(substream);
        snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
        snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
+       if (is_pro_rate_locked(ice)) {
+               runtime->hw.rate_min = PRO_RATE_DEFAULT;
+               runtime->hw.rate_max = PRO_RATE_DEFAULT;
+       }
 
        if (ice->spdif.ops.open)
                ice->spdif.ops.open(ice, substream);
@@ -1197,6 +1201,11 @@ static int snd_ice1712_capture_pro_open(struct snd_pcm_substream *substream)
        snd_pcm_set_sync(substream);
        snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
        snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
+       if (is_pro_rate_locked(ice)) {
+               runtime->hw.rate_min = PRO_RATE_DEFAULT;
+               runtime->hw.rate_max = PRO_RATE_DEFAULT;
+       }
+
        return 0;
 }
 
index ae29073eea93f94f283411c68f21aef8956791cf..c1498fa5545fe9c52814d152e90e19b3bb95543d 100644 (file)
@@ -94,7 +94,7 @@ MODULE_PARM_DESC(model, "Use the given board model.");
 
 
 /* Both VT1720 and VT1724 have the same PCI IDs */
-static const struct pci_device_id snd_vt1724_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_vt1724_ids) = {
        { PCI_VDEVICE(ICE, PCI_DEVICE_ID_VT1724), 0 },
        { 0, }
 };
index b990143636f1699bb9e0815de7501738aa8d4b59..6433e65c9507d20a65be6c0b14af1275c30e0c40 100644 (file)
@@ -420,7 +420,7 @@ struct intel8x0 {
        u32 int_sta_mask;               /* interrupt status mask */
 };
 
-static struct pci_device_id snd_intel8x0_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_intel8x0_ids) = {
        { PCI_VDEVICE(INTEL, 0x2415), DEVICE_INTEL },   /* 82801AA */
        { PCI_VDEVICE(INTEL, 0x2425), DEVICE_INTEL },   /* 82901AB */
        { PCI_VDEVICE(INTEL, 0x2445), DEVICE_INTEL },   /* 82801BA */
index 9e7d12e7673f52abc3d02518da23a51c6d0ff59a..13cec1e5ced9634300e8ca4a50678f4e86eb6674 100644 (file)
@@ -219,7 +219,7 @@ struct intel8x0m {
        unsigned int pcm_pos_shift;
 };
 
-static struct pci_device_id snd_intel8x0m_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_intel8x0m_ids) = {
        { PCI_VDEVICE(INTEL, 0x2416), DEVICE_INTEL },   /* 82801AA */
        { PCI_VDEVICE(INTEL, 0x2426), DEVICE_INTEL },   /* 82901AB */
        { PCI_VDEVICE(INTEL, 0x2446), DEVICE_INTEL },   /* 82801BA */
index 7cc38a11e9978c683f96fc55be8014754d694a34..6d795700be79123c131698f9f2b750c830e582f9 100644 (file)
@@ -418,7 +418,7 @@ module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable Korg 1212 soundcard.");
 MODULE_AUTHOR("Haroldo Gamal <gamal@alternex.com.br>");
 
-static struct pci_device_id snd_korg1212_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_korg1212_ids) = {
        {
                .vendor    = 0x10b5,
                .device    = 0x906d,
index 11b8c6514b3d8ecf5da061687d9c949e0d771d5a..0cca56038cd94d406fc4150f5494855916677afc 100644 (file)
@@ -55,7 +55,7 @@ static const char card_name[] = "LX6464ES";
 
 #define PCI_DEVICE_ID_PLX_LX6464ES             PCI_DEVICE_ID_PLX_9056
 
-static struct pci_device_id snd_lx6464es_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_lx6464es_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_LX6464ES),
          .subvendor = PCI_VENDOR_ID_DIGIGRAM,
          .subdevice = PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_SERIAL_SUBSYSTEM
index 75283fbb4b3fd1723d62a73baf663c14f37f41d3..b64e78139d632c2be13178981efb1b80069df73a 100644 (file)
@@ -861,7 +861,7 @@ struct snd_m3 {
 /*
  * pci ids
  */
-static struct pci_device_id snd_m3_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_m3_ids) = {
        {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ALLEGRO_1, PCI_ANY_ID, PCI_ANY_ID,
         PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0},
        {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ALLEGRO, PCI_ANY_ID, PCI_ANY_ID,
index a83d1968a8450f49816add1bf2bbc2ffbba962c6..7e8e7da592a98e01faf4804e6983dba9fc07878c 100644 (file)
@@ -60,7 +60,7 @@ MODULE_PARM_DESC(enable, "Enable Digigram " CARD_NAME " soundcard.");
 /*
  */
 
-static struct pci_device_id snd_mixart_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_mixart_ids) = {
        { PCI_VDEVICE(MOTOROLA, 0x0003), 0, }, /* MC8240 */
        { 0, }
 };
index 97a0731331a15f6ae2a4be6d16acce0f5e85915d..5a60492ac7b35f449ceacccecec45b65457d22a6 100644 (file)
@@ -262,7 +262,7 @@ struct nm256 {
 /*
  * PCI ids
  */
-static struct pci_device_id snd_nm256_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_nm256_ids) = {
        {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO), 0},
        {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO), 0},
        {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO), 0},
index 389941cf6100226f892903cfc20cdb6932fd570d..acd8f15f7bff43226a534633adeb515c3ba1021b 100644 (file)
@@ -2,7 +2,7 @@ snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o
 snd-hifier-objs := hifier.o
 snd-oxygen-objs := oxygen.o
 snd-virtuoso-objs := virtuoso.o xonar_lib.o \
-       xonar_pcm179x.o xonar_cs43xx.o xonar_hdmi.o
+       xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o
 
 obj-$(CONFIG_SND_OXYGEN_LIB) += snd-oxygen-lib.o
 obj-$(CONFIG_SND_HIFIER) += snd-hifier.o
index e3c229b63311ffc1af8178e18442340c6759c1af..5a87d683691fe0052073674030514347b1326ed3 100644 (file)
@@ -48,7 +48,7 @@ MODULE_PARM_DESC(id, "ID string");
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "enable card");
 
-static struct pci_device_id hifier_ids[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(hifier_ids) = {
        { OXYGEN_PCI_SUBID(0x14c3, 0x1710) },
        { OXYGEN_PCI_SUBID(0x14c3, 0x1711) },
        { OXYGEN_PCI_SUBID_BROKEN_EEPROM },
index acbedebcffd92afc8274ac531db746f487f299e9..289cb4dacfc79ec012b6efb174054efaa0afe855 100644 (file)
@@ -72,7 +72,7 @@ enum {
        MODEL_CLARO_HALO,       /* HT-Omega Claro halo */
 };
 
-static struct pci_device_id oxygen_ids[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = {
        { OXYGEN_PCI_SUBID(0x10b0, 0x0216), .driver_data = MODEL_CMEDIA_REF },
        { OXYGEN_PCI_SUBID(0x10b0, 0x0218), .driver_data = MODEL_CMEDIA_REF },
        { OXYGEN_PCI_SUBID(0x10b0, 0x0219), .driver_data = MODEL_CMEDIA_REF },
index 6accaf9580b2c6cd556c93d99a4a8fda12449229..f03a2f2cffee88911e9c11db08c5dd7dd8087b55 100644 (file)
@@ -40,7 +40,7 @@ MODULE_PARM_DESC(id, "ID string");
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "enable card");
 
-static struct pci_device_id xonar_ids[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(xonar_ids) = {
        { OXYGEN_PCI_SUBID(0x1043, 0x8269) },
        { OXYGEN_PCI_SUBID(0x1043, 0x8275) },
        { OXYGEN_PCI_SUBID(0x1043, 0x82b7) },
@@ -49,6 +49,7 @@ static struct pci_device_id xonar_ids[] __devinitdata = {
        { OXYGEN_PCI_SUBID(0x1043, 0x834f) },
        { OXYGEN_PCI_SUBID(0x1043, 0x835c) },
        { OXYGEN_PCI_SUBID(0x1043, 0x835d) },
+       { OXYGEN_PCI_SUBID(0x1043, 0x838e) },
        { OXYGEN_PCI_SUBID_BROKEN_EEPROM },
        { }
 };
@@ -61,6 +62,8 @@ static int __devinit get_xonar_model(struct oxygen *chip,
                return 0;
        if (get_xonar_cs43xx_model(chip, id) >= 0)
                return 0;
+       if (get_xonar_wm87x6_model(chip, id) >= 0)
+               return 0;
        return -EINVAL;
 }
 
diff --git a/sound/pci/oxygen/wm8766.h b/sound/pci/oxygen/wm8766.h
new file mode 100644 (file)
index 0000000..e0e849a
--- /dev/null
@@ -0,0 +1,73 @@
+#ifndef WM8766_H_INCLUDED
+#define WM8766_H_INCLUDED
+
+#define WM8766_LDA1            0x00
+#define WM8766_RDA1            0x01
+#define WM8766_DAC_CTRL                0x02
+#define WM8766_INT_CTRL                0x03
+#define WM8766_LDA2            0x04
+#define WM8766_RDA2            0x05
+#define WM8766_LDA3            0x06
+#define WM8766_RDA3            0x07
+#define WM8766_MASTDA          0x08
+#define WM8766_DAC_CTRL2       0x09
+#define WM8766_DAC_CTRL3       0x0a
+#define WM8766_MUTE1           0x0c
+#define WM8766_MUTE2           0x0f
+#define WM8766_RESET           0x1f
+
+/* LDAx/RDAx/MASTDA */
+#define WM8766_ATT_MASK                0x0ff
+#define WM8766_UPDATE          0x100
+/* DAC_CTRL */
+#define WM8766_MUTEALL         0x001
+#define WM8766_DEEMPALL                0x002
+#define WM8766_PWDN            0x004
+#define WM8766_ATC             0x008
+#define WM8766_IZD             0x010
+#define WM8766_PL_LEFT_MASK    0x060
+#define WM8766_PL_LEFT_MUTE    0x000
+#define WM8766_PL_LEFT_LEFT    0x020
+#define WM8766_PL_LEFT_RIGHT   0x040
+#define WM8766_PL_LEFT_LRMIX   0x060
+#define WM8766_PL_RIGHT_MASK   0x180
+#define WM8766_PL_RIGHT_MUTE   0x000
+#define WM8766_PL_RIGHT_LEFT   0x080
+#define WM8766_PL_RIGHT_RIGHT  0x100
+#define WM8766_PL_RIGHT_LRMIX  0x180
+/* INT_CTRL */
+#define WM8766_FMT_MASK                0x003
+#define WM8766_FMT_RJUST       0x000
+#define WM8766_FMT_LJUST       0x001
+#define WM8766_FMT_I2S         0x002
+#define WM8766_FMT_DSP         0x003
+#define WM8766_LRP             0x004
+#define WM8766_BCP             0x008
+#define WM8766_IWL_MASK                0x030
+#define WM8766_IWL_16          0x000
+#define WM8766_IWL_20          0x010
+#define WM8766_IWL_24          0x020
+#define WM8766_IWL_32          0x030
+#define WM8766_PHASE_MASK      0x1c0
+/* DAC_CTRL2 */
+#define WM8766_ZCD             0x001
+#define WM8766_DZFM_MASK       0x006
+#define WM8766_DMUTE_MASK      0x038
+#define WM8766_DEEMP_MASK      0x1c0
+/* DAC_CTRL3 */
+#define WM8766_DACPD_MASK      0x00e
+#define WM8766_PWRDNALL                0x010
+#define WM8766_MS              0x020
+#define WM8766_RATE_MASK       0x1c0
+#define WM8766_RATE_128                0x000
+#define WM8766_RATE_192                0x040
+#define WM8766_RATE_256                0x080
+#define WM8766_RATE_384                0x0c0
+#define WM8766_RATE_512                0x100
+#define WM8766_RATE_768                0x140
+/* MUTE1 */
+#define WM8766_MPD1            0x040
+/* MUTE2 */
+#define WM8766_MPD2            0x020
+
+#endif
diff --git a/sound/pci/oxygen/wm8776.h b/sound/pci/oxygen/wm8776.h
new file mode 100644 (file)
index 0000000..1a96f56
--- /dev/null
@@ -0,0 +1,177 @@
+#ifndef WM8776_H_INCLUDED
+#define WM8776_H_INCLUDED
+
+/*
+ * the following register names are from:
+ * wm8776.h  --  WM8776 ASoC driver
+ *
+ * Copyright 2009 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.
+ */
+
+#define WM8776_HPLVOL          0x00
+#define WM8776_HPRVOL          0x01
+#define WM8776_HPMASTER                0x02
+#define WM8776_DACLVOL         0x03
+#define WM8776_DACRVOL         0x04
+#define WM8776_DACMASTER       0x05
+#define WM8776_PHASESWAP       0x06
+#define WM8776_DACCTRL1                0x07
+#define WM8776_DACMUTE         0x08
+#define WM8776_DACCTRL2                0x09
+#define WM8776_DACIFCTRL       0x0a
+#define WM8776_ADCIFCTRL       0x0b
+#define WM8776_MSTRCTRL                0x0c
+#define WM8776_PWRDOWN         0x0d
+#define WM8776_ADCLVOL         0x0e
+#define WM8776_ADCRVOL         0x0f
+#define WM8776_ALCCTRL1                0x10
+#define WM8776_ALCCTRL2                0x11
+#define WM8776_ALCCTRL3                0x12
+#define WM8776_NOISEGATE       0x13
+#define WM8776_LIMITER         0x14
+#define WM8776_ADCMUX          0x15
+#define WM8776_OUTMUX          0x16
+#define WM8776_RESET           0x17
+
+
+/* HPLVOL/HPRVOL/HPMASTER */
+#define WM8776_HPATT_MASK      0x07f
+#define WM8776_HPZCEN          0x080
+#define WM8776_UPDATE          0x100
+
+/* DACLVOL/DACRVOL/DACMASTER */
+#define WM8776_DATT_MASK       0x0ff
+/*#define WM8776_UPDATE                0x100*/
+
+/* PHASESWAP */
+#define WM8776_PH_MASK         0x003
+
+/* DACCTRL1 */
+#define WM8776_DZCEN           0x001
+#define WM8776_ATC             0x002
+#define WM8776_IZD             0x004
+#define WM8776_TOD             0x008
+#define WM8776_PL_LEFT_MASK    0x030
+#define WM8776_PL_LEFT_MUTE    0x000
+#define WM8776_PL_LEFT_LEFT    0x010
+#define WM8776_PL_LEFT_RIGHT   0x020
+#define WM8776_PL_LEFT_LRMIX   0x030
+#define WM8776_PL_RIGHT_MASK   0x0c0
+#define WM8776_PL_RIGHT_MUTE   0x000
+#define WM8776_PL_RIGHT_LEFT   0x040
+#define WM8776_PL_RIGHT_RIGHT  0x080
+#define WM8776_PL_RIGHT_LRMIX  0x0c0
+
+/* DACMUTE */
+#define WM8776_DMUTE           0x001
+
+/* DACCTRL2 */
+#define WM8776_DEEMPH          0x001
+#define WM8776_DZFM_MASK       0x006
+#define WM8776_DZFM_NONE       0x000
+#define WM8776_DZFM_LR         0x002
+#define WM8776_DZFM_BOTH       0x004
+#define WM8776_DZFM_EITHER     0x006
+
+/* DACIFCTRL */
+#define WM8776_DACFMT_MASK     0x003
+#define WM8776_DACFMT_RJUST    0x000
+#define WM8776_DACFMT_LJUST    0x001
+#define WM8776_DACFMT_I2S      0x002
+#define WM8776_DACFMT_DSP      0x003
+#define WM8776_DACLRP          0x004
+#define WM8776_DACBCP          0x008
+#define WM8776_DACWL_MASK      0x030
+#define WM8776_DACWL_16                0x000
+#define WM8776_DACWL_20                0x010
+#define WM8776_DACWL_24                0x020
+#define WM8776_DACWL_32                0x030
+
+/* ADCIFCTRL */
+#define WM8776_ADCFMT_MASK     0x003
+#define WM8776_ADCFMT_RJUST    0x000
+#define WM8776_ADCFMT_LJUST    0x001
+#define WM8776_ADCFMT_I2S      0x002
+#define WM8776_ADCFMT_DSP      0x003
+#define WM8776_ADCLRP          0x004
+#define WM8776_ADCBCP          0x008
+#define WM8776_ADCWL_MASK      0x030
+#define WM8776_ADCWL_16                0x000
+#define WM8776_ADCWL_20                0x010
+#define WM8776_ADCWL_24                0x020
+#define WM8776_ADCWL_32                0x030
+#define WM8776_ADCMCLK         0x040
+#define WM8776_ADCHPD          0x100
+
+/* MSTRCTRL */
+#define WM8776_ADCRATE_MASK    0x007
+#define WM8776_ADCRATE_256     0x002
+#define WM8776_ADCRATE_384     0x003
+#define WM8776_ADCRATE_512     0x004
+#define WM8776_ADCRATE_768     0x005
+#define WM8776_ADCOSR          0x008
+#define WM8776_DACRATE_MASK    0x070
+#define WM8776_DACRATE_128     0x000
+#define WM8776_DACRATE_192     0x010
+#define WM8776_DACRATE_256     0x020
+#define WM8776_DACRATE_384     0x030
+#define WM8776_DACRATE_512     0x040
+#define WM8776_DACRATE_768     0x050
+#define WM8776_DACMS           0x080
+#define WM8776_ADCMS           0x100
+
+/* PWRDOWN */
+#define WM8776_PDWN            0x001
+#define WM8776_ADCPD           0x002
+#define WM8776_DACPD           0x004
+#define WM8776_HPPD            0x008
+#define WM8776_AINPD           0x040
+
+/* ADCLVOL/ADCRVOL */
+#define WM8776_AGMASK          0x0ff
+#define WM8776_ZCA             0x100
+
+/* ALCCTRL1 */
+#define WM8776_LCT_MASK                0x00f
+#define WM8776_MAXGAIN_MASK    0x070
+#define WM8776_LCSEL_MASK      0x180
+#define WM8776_LCSEL_LIMITER   0x000
+#define WM8776_LCSEL_ALC_RIGHT 0x080
+#define WM8776_LCSEL_ALC_LEFT  0x100
+#define WM8776_LCSEL_ALC_STEREO        0x180
+
+/* ALCCTRL2 */
+#define WM8776_HLD_MASK                0x00f
+#define WM8776_ALCZC           0x080
+#define WM8776_LCEN            0x100
+
+/* ALCCTRL3 */
+#define WM8776_ATK_MASK                0x00f
+#define WM8776_DCY_MASK                0x0f0
+
+/* NOISEGATE */
+#define WM8776_NGAT            0x001
+#define WM8776_NGTH_MASK       0x01c
+
+/* LIMITER */
+#define WM8776_MAXATTEN_MASK   0x00f
+#define WM8776_TRANWIN_MASK    0x070
+
+/* ADCMUX */
+#define WM8776_AMX_MASK                0x01f
+#define WM8776_MUTERA          0x040
+#define WM8776_MUTELA          0x080
+#define WM8776_LRBOTH          0x100
+
+/* OUTMUX */
+#define WM8776_MX_DAC          0x001
+#define WM8776_MX_AUX          0x002
+#define WM8776_MX_BYPASS       0x004
+
+#endif
index 89b3ed814d64b0d673dd728bcc3dedb7a826516e..b35343b0a9a58cb3444faf02a832b65e888af04c 100644 (file)
@@ -35,6 +35,8 @@ int get_xonar_pcm179x_model(struct oxygen *chip,
                            const struct pci_device_id *id);
 int get_xonar_cs43xx_model(struct oxygen *chip,
                           const struct pci_device_id *id);
+int get_xonar_wm87x6_model(struct oxygen *chip,
+                          const struct pci_device_id *id);
 
 /* HDMI helper functions */
 
diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c
new file mode 100644 (file)
index 0000000..7754db1
--- /dev/null
@@ -0,0 +1,1021 @@
+/*
+ * card driver for models with WM8776/WM8766 DACs (Xonar DS)
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ *
+ *
+ *  This driver is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License, version 2.
+ *
+ *  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 driver; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Xonar DS
+ * --------
+ *
+ * CMI8788:
+ *
+ * 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
+ */
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include "xonar.h"
+#include "wm8776.h"
+#include "wm8766.h"
+
+#define GPIO_DS_HP_DETECT      0x0010
+#define GPIO_DS_INPUT_ROUTE    0x0040
+#define GPIO_DS_OUTPUT_ENABLE  0x0180
+
+#define LC_CONTROL_LIMITER     0x40000000
+#define LC_CONTROL_ALC         0x20000000
+
+struct xonar_wm87x6 {
+       struct xonar_generic generic;
+       u16 wm8776_regs[0x17];
+       u16 wm8766_regs[0x10];
+       struct snd_kcontrol *lc_controls[13];
+};
+
+static void wm8776_write(struct oxygen *chip,
+                        unsigned int reg, unsigned int value)
+{
+       struct xonar_wm87x6 *data = chip->model_data;
+
+       oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
+                        OXYGEN_SPI_DATA_LENGTH_2 |
+                        OXYGEN_SPI_CLOCK_160 |
+                        (1 << OXYGEN_SPI_CODEC_SHIFT) |
+                        OXYGEN_SPI_CEN_LATCH_CLOCK_LO,
+                        (reg << 9) | value);
+       if (reg < ARRAY_SIZE(data->wm8776_regs)) {
+               if (reg >= WM8776_HPLVOL || reg <= WM8776_DACMASTER)
+                       value &= ~WM8776_UPDATE;
+               data->wm8776_regs[reg] = value;
+       }
+}
+
+static void wm8776_write_cached(struct oxygen *chip,
+                               unsigned int reg, unsigned int value)
+{
+       struct xonar_wm87x6 *data = chip->model_data;
+
+       if (reg >= ARRAY_SIZE(data->wm8776_regs) ||
+           value != data->wm8776_regs[reg])
+               wm8776_write(chip, reg, value);
+}
+
+static void wm8766_write(struct oxygen *chip,
+                        unsigned int reg, unsigned int value)
+{
+       struct xonar_wm87x6 *data = chip->model_data;
+
+       oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
+                        OXYGEN_SPI_DATA_LENGTH_2 |
+                        OXYGEN_SPI_CLOCK_160 |
+                        (0 << OXYGEN_SPI_CODEC_SHIFT) |
+                        OXYGEN_SPI_CEN_LATCH_CLOCK_LO,
+                        (reg << 9) | value);
+       if (reg < ARRAY_SIZE(data->wm8766_regs))
+               data->wm8766_regs[reg] = value;
+}
+
+static void wm8766_write_cached(struct oxygen *chip,
+                               unsigned int reg, unsigned int value)
+{
+       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;
+               wm8766_write(chip, reg, value);
+       }
+}
+
+static void wm8776_registers_init(struct oxygen *chip)
+{
+       struct xonar_wm87x6 *data = chip->model_data;
+
+       wm8776_write(chip, WM8776_RESET, 0);
+       wm8776_write(chip, WM8776_DACCTRL1, WM8776_DZCEN |
+                    WM8776_PL_LEFT_LEFT | WM8776_PL_RIGHT_RIGHT);
+       wm8776_write(chip, WM8776_DACMUTE, chip->dac_mute ? WM8776_DMUTE : 0);
+       wm8776_write(chip, WM8776_DACIFCTRL,
+                    WM8776_DACFMT_LJUST | WM8776_DACWL_24);
+       wm8776_write(chip, WM8776_ADCIFCTRL,
+                    data->wm8776_regs[WM8776_ADCIFCTRL]);
+       wm8776_write(chip, WM8776_MSTRCTRL, data->wm8776_regs[WM8776_MSTRCTRL]);
+       wm8776_write(chip, WM8776_PWRDOWN, data->wm8776_regs[WM8776_PWRDOWN]);
+       wm8776_write(chip, WM8776_HPLVOL, data->wm8776_regs[WM8776_HPLVOL]);
+       wm8776_write(chip, WM8776_HPRVOL, data->wm8776_regs[WM8776_HPRVOL] |
+                    WM8776_UPDATE);
+       wm8776_write(chip, WM8776_ADCLVOL, data->wm8776_regs[WM8776_ADCLVOL]);
+       wm8776_write(chip, WM8776_ADCRVOL, data->wm8776_regs[WM8776_ADCRVOL]);
+       wm8776_write(chip, WM8776_ADCMUX, data->wm8776_regs[WM8776_ADCMUX]);
+       wm8776_write(chip, WM8776_DACLVOL, chip->dac_volume[0]);
+       wm8776_write(chip, WM8776_DACRVOL, chip->dac_volume[1] | WM8776_UPDATE);
+}
+
+static void wm8766_registers_init(struct oxygen *chip)
+{
+       wm8766_write(chip, WM8766_RESET, 0);
+       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));
+       wm8766_write(chip, WM8766_LDA1, chip->dac_volume[2]);
+       wm8766_write(chip, WM8766_RDA1, chip->dac_volume[3]);
+       wm8766_write(chip, WM8766_LDA2, chip->dac_volume[4]);
+       wm8766_write(chip, WM8766_RDA2, chip->dac_volume[5]);
+       wm8766_write(chip, WM8766_LDA3, chip->dac_volume[6]);
+       wm8766_write(chip, WM8766_RDA3, chip->dac_volume[7] | WM8766_UPDATE);
+}
+
+static void wm8776_init(struct oxygen *chip)
+{
+       struct xonar_wm87x6 *data = chip->model_data;
+
+       data->wm8776_regs[WM8776_HPLVOL] = (0x79 - 60) | WM8776_HPZCEN;
+       data->wm8776_regs[WM8776_HPRVOL] = (0x79 - 60) | WM8776_HPZCEN;
+       data->wm8776_regs[WM8776_ADCIFCTRL] =
+               WM8776_ADCFMT_LJUST | WM8776_ADCWL_24 | WM8776_ADCMCLK;
+       data->wm8776_regs[WM8776_MSTRCTRL] =
+               WM8776_ADCRATE_256 | WM8776_DACRATE_256;
+       data->wm8776_regs[WM8776_PWRDOWN] = WM8776_HPPD;
+       data->wm8776_regs[WM8776_ADCLVOL] = 0xa5 | WM8776_ZCA;
+       data->wm8776_regs[WM8776_ADCRVOL] = 0xa5 | WM8776_ZCA;
+       data->wm8776_regs[WM8776_ADCMUX] = 0x001;
+       wm8776_registers_init(chip);
+}
+
+static void xonar_ds_init(struct oxygen *chip)
+{
+       struct xonar_wm87x6 *data = chip->model_data;
+
+       data->generic.anti_pop_delay = 300;
+       data->generic.output_enable_bit = GPIO_DS_OUTPUT_ENABLE;
+
+       wm8776_init(chip);
+       wm8766_registers_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_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_component_add(chip->card, "WM8776");
+       snd_component_add(chip->card, "WM8766");
+}
+
+static void xonar_ds_cleanup(struct oxygen *chip)
+{
+       xonar_disable_output(chip);
+}
+
+static void xonar_ds_suspend(struct oxygen *chip)
+{
+       xonar_ds_cleanup(chip);
+}
+
+static void xonar_ds_resume(struct oxygen *chip)
+{
+       wm8776_registers_init(chip);
+       wm8766_registers_init(chip);
+       xonar_enable_output(chip);
+}
+
+static void wm8776_adc_hardware_filter(unsigned int channel,
+                                      struct snd_pcm_hardware *hardware)
+{
+       if (channel == PCM_A) {
+               hardware->rates = SNDRV_PCM_RATE_32000 |
+                                 SNDRV_PCM_RATE_44100 |
+                                 SNDRV_PCM_RATE_48000 |
+                                 SNDRV_PCM_RATE_64000 |
+                                 SNDRV_PCM_RATE_88200 |
+                                 SNDRV_PCM_RATE_96000;
+               hardware->rate_max = 96000;
+       }
+}
+
+static void set_wm87x6_dac_params(struct oxygen *chip,
+                                 struct snd_pcm_hw_params *params)
+{
+}
+
+static void set_wm8776_adc_params(struct oxygen *chip,
+                                 struct snd_pcm_hw_params *params)
+{
+       u16 reg;
+
+       reg = WM8776_ADCRATE_256 | WM8776_DACRATE_256;
+       if (params_rate(params) > 48000)
+               reg |= WM8776_ADCOSR;
+       wm8776_write_cached(chip, WM8776_MSTRCTRL, reg);
+}
+
+static void update_wm8776_volume(struct oxygen *chip)
+{
+       struct xonar_wm87x6 *data = chip->model_data;
+       u8 to_change;
+
+       if (chip->dac_volume[0] == chip->dac_volume[1]) {
+               if (chip->dac_volume[0] != data->wm8776_regs[WM8776_DACLVOL] ||
+                   chip->dac_volume[1] != data->wm8776_regs[WM8776_DACRVOL]) {
+                       wm8776_write(chip, WM8776_DACMASTER,
+                                    chip->dac_volume[0] | WM8776_UPDATE);
+                       data->wm8776_regs[WM8776_DACLVOL] = chip->dac_volume[0];
+                       data->wm8776_regs[WM8776_DACRVOL] = chip->dac_volume[0];
+               }
+       } else {
+               to_change = (chip->dac_volume[0] !=
+                            data->wm8776_regs[WM8776_DACLVOL]) << 0;
+               to_change |= (chip->dac_volume[1] !=
+                             data->wm8776_regs[WM8776_DACLVOL]) << 1;
+               if (to_change & 1)
+                       wm8776_write(chip, WM8776_DACLVOL, chip->dac_volume[0] |
+                                    ((to_change & 2) ? 0 : WM8776_UPDATE));
+               if (to_change & 2)
+                       wm8776_write(chip, WM8776_DACRVOL,
+                                    chip->dac_volume[1] | WM8776_UPDATE);
+       }
+}
+
+static void update_wm87x6_volume(struct oxygen *chip)
+{
+       static const u8 wm8766_regs[6] = {
+               WM8766_LDA1, WM8766_RDA1,
+               WM8766_LDA2, WM8766_RDA2,
+               WM8766_LDA3, WM8766_RDA3,
+       };
+       struct xonar_wm87x6 *data = chip->model_data;
+       unsigned int i;
+       u8 to_change;
+
+       update_wm8776_volume(chip);
+       if (chip->dac_volume[2] == chip->dac_volume[3] &&
+           chip->dac_volume[2] == chip->dac_volume[4] &&
+           chip->dac_volume[2] == chip->dac_volume[5] &&
+           chip->dac_volume[2] == chip->dac_volume[6] &&
+           chip->dac_volume[2] == chip->dac_volume[7]) {
+               to_change = 0;
+               for (i = 0; i < 6; ++i)
+                       if (chip->dac_volume[2] !=
+                           data->wm8766_regs[wm8766_regs[i]])
+                               to_change = 1;
+               if (to_change) {
+                       wm8766_write(chip, WM8766_MASTDA,
+                                    chip->dac_volume[2] | WM8766_UPDATE);
+                       for (i = 0; i < 6; ++i)
+                               data->wm8766_regs[wm8766_regs[i]] =
+                                       chip->dac_volume[2];
+               }
+       } else {
+               to_change = 0;
+               for (i = 0; i < 6; ++i)
+                       to_change |= (chip->dac_volume[2 + i] !=
+                                     data->wm8766_regs[wm8766_regs[i]]) << i;
+               for (i = 0; i < 6; ++i)
+                       if (to_change & (1 << i))
+                               wm8766_write(chip, wm8766_regs[i],
+                                            chip->dac_volume[2 + i] |
+                                            ((to_change & (0x3e << i))
+                                             ? 0 : WM8766_UPDATE));
+       }
+}
+
+static void update_wm8776_mute(struct oxygen *chip)
+{
+       wm8776_write_cached(chip, WM8776_DACMUTE,
+                           chip->dac_mute ? WM8776_DMUTE : 0);
+}
+
+static void update_wm87x6_mute(struct oxygen *chip)
+{
+       update_wm8776_mute(chip);
+       wm8766_write_cached(chip, WM8766_DAC_CTRL2, WM8766_ZCD |
+                           (chip->dac_mute ? WM8766_DMUTE_MASK : 0));
+}
+
+static void xonar_ds_gpio_changed(struct oxygen *chip)
+{
+       u16 bits;
+
+       bits = oxygen_read16(chip, OXYGEN_GPIO_DATA);
+       snd_printk(KERN_INFO "HP detect: %d\n", !!(bits & GPIO_DS_HP_DETECT));
+}
+
+static int wm8776_bit_switch_get(struct snd_kcontrol *ctl,
+                                struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct xonar_wm87x6 *data = chip->model_data;
+       u16 bit = ctl->private_value & 0xffff;
+       unsigned int reg_index = (ctl->private_value >> 16) & 0xff;
+       bool invert = (ctl->private_value >> 24) & 1;
+
+       value->value.integer.value[0] =
+               ((data->wm8776_regs[reg_index] & bit) != 0) ^ invert;
+       return 0;
+}
+
+static int wm8776_bit_switch_put(struct snd_kcontrol *ctl,
+                                struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct xonar_wm87x6 *data = chip->model_data;
+       u16 bit = ctl->private_value & 0xffff;
+       u16 reg_value;
+       unsigned int reg_index = (ctl->private_value >> 16) & 0xff;
+       bool invert = (ctl->private_value >> 24) & 1;
+       int changed;
+
+       mutex_lock(&chip->mutex);
+       reg_value = data->wm8776_regs[reg_index] & ~bit;
+       if (value->value.integer.value[0] ^ invert)
+               reg_value |= bit;
+       changed = reg_value != data->wm8776_regs[reg_index];
+       if (changed)
+               wm8776_write(chip, reg_index, reg_value);
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+static int wm8776_field_enum_info(struct snd_kcontrol *ctl,
+                                 struct snd_ctl_elem_info *info)
+{
+       static const char *const hld[16] = {
+               "0 ms", "2.67 ms", "5.33 ms", "10.6 ms",
+               "21.3 ms", "42.7 ms", "85.3 ms", "171 ms",
+               "341 ms", "683 ms", "1.37 s", "2.73 s",
+               "5.46 s", "10.9 s", "21.8 s", "43.7 s",
+       };
+       static const char *const atk_lim[11] = {
+               "0.25 ms", "0.5 ms", "1 ms", "2 ms",
+               "4 ms", "8 ms", "16 ms", "32 ms",
+               "64 ms", "128 ms", "256 ms",
+       };
+       static const char *const atk_alc[11] = {
+               "8.40 ms", "16.8 ms", "33.6 ms", "67.2 ms",
+               "134 ms", "269 ms", "538 ms", "1.08 s",
+               "2.15 s", "4.3 s", "8.6 s",
+       };
+       static const char *const dcy_lim[11] = {
+               "1.2 ms", "2.4 ms", "4.8 ms", "9.6 ms",
+               "19.2 ms", "38.4 ms", "76.8 ms", "154 ms",
+               "307 ms", "614 ms", "1.23 s",
+       };
+       static const char *const dcy_alc[11] = {
+               "33.5 ms", "67.0 ms", "134 ms", "268 ms",
+               "536 ms", "1.07 s", "2.14 s", "4.29 s",
+               "8.58 s", "17.2 s", "34.3 s",
+       };
+       static const char *const tranwin[8] = {
+               "0 us", "62.5 us", "125 us", "250 us",
+               "500 us", "1 ms", "2 ms", "4 ms",
+       };
+       u8 max;
+       const char *const *names;
+
+       max = (ctl->private_value >> 12) & 0xf;
+       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       info->count = 1;
+       info->value.enumerated.items = max + 1;
+       if (info->value.enumerated.item > max)
+               info->value.enumerated.item = max;
+       switch ((ctl->private_value >> 24) & 0x1f) {
+       case WM8776_ALCCTRL2:
+               names = hld;
+               break;
+       case WM8776_ALCCTRL3:
+               if (((ctl->private_value >> 20) & 0xf) == 0) {
+                       if (ctl->private_value & LC_CONTROL_LIMITER)
+                               names = atk_lim;
+                       else
+                               names = atk_alc;
+               } else {
+                       if (ctl->private_value & LC_CONTROL_LIMITER)
+                               names = dcy_lim;
+                       else
+                               names = dcy_alc;
+               }
+               break;
+       case WM8776_LIMITER:
+               names = tranwin;
+               break;
+       default:
+               return -ENXIO;
+       }
+       strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
+       return 0;
+}
+
+static int wm8776_field_volume_info(struct snd_kcontrol *ctl,
+                                   struct snd_ctl_elem_info *info)
+{
+       info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       info->count = 1;
+       info->value.integer.min = (ctl->private_value >> 8) & 0xf;
+       info->value.integer.max = (ctl->private_value >> 12) & 0xf;
+       return 0;
+}
+
+static void wm8776_field_set_from_ctl(struct snd_kcontrol *ctl)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct xonar_wm87x6 *data = chip->model_data;
+       unsigned int value, reg_index, mode;
+       u8 min, max, shift;
+       u16 mask, reg_value;
+       bool invert;
+
+       if ((data->wm8776_regs[WM8776_ALCCTRL1] & WM8776_LCSEL_MASK) ==
+           WM8776_LCSEL_LIMITER)
+               mode = LC_CONTROL_LIMITER;
+       else
+               mode = LC_CONTROL_ALC;
+       if (!(ctl->private_value & mode))
+               return;
+
+       value = ctl->private_value & 0xf;
+       min = (ctl->private_value >> 8) & 0xf;
+       max = (ctl->private_value >> 12) & 0xf;
+       mask = (ctl->private_value >> 16) & 0xf;
+       shift = (ctl->private_value >> 20) & 0xf;
+       reg_index = (ctl->private_value >> 24) & 0x1f;
+       invert = (ctl->private_value >> 29) & 0x1;
+
+       if (invert)
+               value = max - (value - min);
+       reg_value = data->wm8776_regs[reg_index];
+       reg_value &= ~(mask << shift);
+       reg_value |= value << shift;
+       wm8776_write_cached(chip, reg_index, reg_value);
+}
+
+static int wm8776_field_set(struct snd_kcontrol *ctl, unsigned int value)
+{
+       struct oxygen *chip = ctl->private_data;
+       u8 min, max;
+       int changed;
+
+       min = (ctl->private_value >> 8) & 0xf;
+       max = (ctl->private_value >> 12) & 0xf;
+       if (value < min || value > max)
+               return -EINVAL;
+       mutex_lock(&chip->mutex);
+       changed = value != (ctl->private_value & 0xf);
+       if (changed) {
+               ctl->private_value = (ctl->private_value & ~0xf) | value;
+               wm8776_field_set_from_ctl(ctl);
+       }
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+static int wm8776_field_enum_get(struct snd_kcontrol *ctl,
+                                struct snd_ctl_elem_value *value)
+{
+       value->value.enumerated.item[0] = ctl->private_value & 0xf;
+       return 0;
+}
+
+static int wm8776_field_volume_get(struct snd_kcontrol *ctl,
+                                  struct snd_ctl_elem_value *value)
+{
+       value->value.integer.value[0] = ctl->private_value & 0xf;
+       return 0;
+}
+
+static int wm8776_field_enum_put(struct snd_kcontrol *ctl,
+                                struct snd_ctl_elem_value *value)
+{
+       return wm8776_field_set(ctl, value->value.enumerated.item[0]);
+}
+
+static int wm8776_field_volume_put(struct snd_kcontrol *ctl,
+                                  struct snd_ctl_elem_value *value)
+{
+       return wm8776_field_set(ctl, value->value.integer.value[0]);
+}
+
+static int wm8776_hp_vol_info(struct snd_kcontrol *ctl,
+                             struct snd_ctl_elem_info *info)
+{
+       info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       info->count = 2;
+       info->value.integer.min = 0x79 - 60;
+       info->value.integer.max = 0x7f;
+       return 0;
+}
+
+static int wm8776_hp_vol_get(struct snd_kcontrol *ctl,
+                            struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct xonar_wm87x6 *data = chip->model_data;
+
+       mutex_lock(&chip->mutex);
+       value->value.integer.value[0] =
+               data->wm8776_regs[WM8776_HPLVOL] & WM8776_HPATT_MASK;
+       value->value.integer.value[1] =
+               data->wm8776_regs[WM8776_HPRVOL] & WM8776_HPATT_MASK;
+       mutex_unlock(&chip->mutex);
+       return 0;
+}
+
+static int wm8776_hp_vol_put(struct snd_kcontrol *ctl,
+                            struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct xonar_wm87x6 *data = chip->model_data;
+       u8 to_update;
+
+       mutex_lock(&chip->mutex);
+       to_update = (value->value.integer.value[0] !=
+                    (data->wm8776_regs[WM8776_HPLVOL] & WM8776_HPATT_MASK))
+               << 0;
+       to_update |= (value->value.integer.value[1] !=
+                     (data->wm8776_regs[WM8776_HPRVOL] & WM8776_HPATT_MASK))
+               << 1;
+       if (value->value.integer.value[0] == value->value.integer.value[1]) {
+               if (to_update) {
+                       wm8776_write(chip, WM8776_HPMASTER,
+                                    value->value.integer.value[0] |
+                                    WM8776_HPZCEN | WM8776_UPDATE);
+                       data->wm8776_regs[WM8776_HPLVOL] =
+                               value->value.integer.value[0] | WM8776_HPZCEN;
+                       data->wm8776_regs[WM8776_HPRVOL] =
+                               value->value.integer.value[0] | WM8776_HPZCEN;
+               }
+       } else {
+               if (to_update & 1)
+                       wm8776_write(chip, WM8776_HPLVOL,
+                                    value->value.integer.value[0] |
+                                    WM8776_HPZCEN |
+                                    ((to_update & 2) ? 0 : WM8776_UPDATE));
+               if (to_update & 2)
+                       wm8776_write(chip, WM8776_HPRVOL,
+                                    value->value.integer.value[1] |
+                                    WM8776_HPZCEN | WM8776_UPDATE);
+       }
+       mutex_unlock(&chip->mutex);
+       return to_update != 0;
+}
+
+static int wm8776_input_mux_get(struct snd_kcontrol *ctl,
+                               struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct xonar_wm87x6 *data = chip->model_data;
+       unsigned int mux_bit = ctl->private_value;
+
+       value->value.integer.value[0] =
+               !!(data->wm8776_regs[WM8776_ADCMUX] & mux_bit);
+       return 0;
+}
+
+static int wm8776_input_mux_put(struct snd_kcontrol *ctl,
+                               struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct xonar_wm87x6 *data = chip->model_data;
+       unsigned int mux_bit = ctl->private_value;
+       u16 reg;
+       int changed;
+
+       mutex_lock(&chip->mutex);
+       reg = data->wm8776_regs[WM8776_ADCMUX];
+       if (value->value.integer.value[0]) {
+               reg &= ~0x003;
+               reg |= mux_bit;
+       } else
+               reg &= ~mux_bit;
+       changed = reg != data->wm8776_regs[WM8776_ADCMUX];
+       if (changed) {
+               oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
+                                     reg & 1 ? GPIO_DS_INPUT_ROUTE : 0,
+                                     GPIO_DS_INPUT_ROUTE);
+               wm8776_write(chip, WM8776_ADCMUX, reg);
+       }
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+static int wm8776_input_vol_info(struct snd_kcontrol *ctl,
+                                struct snd_ctl_elem_info *info)
+{
+       info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       info->count = 2;
+       info->value.integer.min = 0xa5;
+       info->value.integer.max = 0xff;
+       return 0;
+}
+
+static int wm8776_input_vol_get(struct snd_kcontrol *ctl,
+                               struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct xonar_wm87x6 *data = chip->model_data;
+
+       mutex_lock(&chip->mutex);
+       value->value.integer.value[0] =
+               data->wm8776_regs[WM8776_ADCLVOL] & WM8776_AGMASK;
+       value->value.integer.value[1] =
+               data->wm8776_regs[WM8776_ADCRVOL] & WM8776_AGMASK;
+       mutex_unlock(&chip->mutex);
+       return 0;
+}
+
+static int wm8776_input_vol_put(struct snd_kcontrol *ctl,
+                               struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct xonar_wm87x6 *data = chip->model_data;
+       int changed = 0;
+
+       mutex_lock(&chip->mutex);
+       changed = (value->value.integer.value[0] !=
+                  (data->wm8776_regs[WM8776_ADCLVOL] & WM8776_AGMASK)) ||
+                 (value->value.integer.value[1] !=
+                  (data->wm8776_regs[WM8776_ADCRVOL] & WM8776_AGMASK));
+       wm8776_write_cached(chip, WM8776_ADCLVOL,
+                           value->value.integer.value[0] | WM8776_ZCA);
+       wm8776_write_cached(chip, WM8776_ADCRVOL,
+                           value->value.integer.value[1] | WM8776_ZCA);
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+static int wm8776_level_control_info(struct snd_kcontrol *ctl,
+                                    struct snd_ctl_elem_info *info)
+{
+       static const char *const names[3] = {
+               "None", "Peak Limiter", "Automatic Level Control"
+       };
+       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       info->count = 1;
+       info->value.enumerated.items = 3;
+       if (info->value.enumerated.item >= 3)
+               info->value.enumerated.item = 2;
+       strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
+       return 0;
+}
+
+static int wm8776_level_control_get(struct snd_kcontrol *ctl,
+                                   struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct xonar_wm87x6 *data = chip->model_data;
+
+       if (!(data->wm8776_regs[WM8776_ALCCTRL2] & WM8776_LCEN))
+               value->value.enumerated.item[0] = 0;
+       else if ((data->wm8776_regs[WM8776_ALCCTRL1] & WM8776_LCSEL_MASK) ==
+                WM8776_LCSEL_LIMITER)
+               value->value.enumerated.item[0] = 1;
+       else
+               value->value.enumerated.item[0] = 2;
+       return 0;
+}
+
+static void activate_control(struct oxygen *chip,
+                            struct snd_kcontrol *ctl, unsigned int mode)
+{
+       unsigned int access;
+
+       if (ctl->private_value & mode)
+               access = 0;
+       else
+               access = SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+       if ((ctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_INACTIVE) != access) {
+               ctl->vd[0].access ^= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+               snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &ctl->id);
+       }
+}
+
+static int wm8776_level_control_put(struct snd_kcontrol *ctl,
+                                   struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct xonar_wm87x6 *data = chip->model_data;
+       unsigned int mode = 0, i;
+       u16 ctrl1, ctrl2;
+       int changed;
+
+       if (value->value.enumerated.item[0] >= 3)
+               return -EINVAL;
+       mutex_lock(&chip->mutex);
+       changed = value->value.enumerated.item[0] != ctl->private_value;
+       if (changed) {
+               ctl->private_value = value->value.enumerated.item[0];
+               ctrl1 = data->wm8776_regs[WM8776_ALCCTRL1];
+               ctrl2 = data->wm8776_regs[WM8776_ALCCTRL2];
+               switch (value->value.enumerated.item[0]) {
+               default:
+                       wm8776_write_cached(chip, WM8776_ALCCTRL2,
+                                           ctrl2 & ~WM8776_LCEN);
+                       break;
+               case 1:
+                       wm8776_write_cached(chip, WM8776_ALCCTRL1,
+                                           (ctrl1 & ~WM8776_LCSEL_MASK) |
+                                           WM8776_LCSEL_LIMITER);
+                       wm8776_write_cached(chip, WM8776_ALCCTRL2,
+                                           ctrl2 | WM8776_LCEN);
+                       mode = LC_CONTROL_LIMITER;
+                       break;
+               case 2:
+                       wm8776_write_cached(chip, WM8776_ALCCTRL1,
+                                           (ctrl1 & ~WM8776_LCSEL_MASK) |
+                                           WM8776_LCSEL_ALC_STEREO);
+                       wm8776_write_cached(chip, WM8776_ALCCTRL2,
+                                           ctrl2 | WM8776_LCEN);
+                       mode = LC_CONTROL_ALC;
+                       break;
+               }
+               for (i = 0; i < ARRAY_SIZE(data->lc_controls); ++i)
+                       activate_control(chip, data->lc_controls[i], mode);
+       }
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
+{
+       static const char *const names[2] = {
+               "None", "High-pass Filter"
+       };
+
+       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       info->count = 1;
+       info->value.enumerated.items = 2;
+       if (info->value.enumerated.item >= 2)
+               info->value.enumerated.item = 1;
+       strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
+       return 0;
+}
+
+static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct xonar_wm87x6 *data = chip->model_data;
+
+       value->value.enumerated.item[0] =
+               !(data->wm8776_regs[WM8776_ADCIFCTRL] & WM8776_ADCHPD);
+       return 0;
+}
+
+static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct xonar_wm87x6 *data = chip->model_data;
+       unsigned int reg;
+       int changed;
+
+       mutex_lock(&chip->mutex);
+       reg = data->wm8776_regs[WM8776_ADCIFCTRL] & ~WM8776_ADCHPD;
+       if (!value->value.enumerated.item[0])
+               reg |= WM8776_ADCHPD;
+       changed = reg != data->wm8776_regs[WM8776_ADCIFCTRL];
+       if (changed)
+               wm8776_write(chip, WM8776_ADCIFCTRL, reg);
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+#define WM8776_BIT_SWITCH(xname, reg, bit, invert, flags) { \
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = xname, \
+       .info = snd_ctl_boolean_mono_info, \
+       .get = wm8776_bit_switch_get, \
+       .put = wm8776_bit_switch_put, \
+       .private_value = ((reg) << 16) | (bit) | ((invert) << 24) | (flags), \
+}
+#define _WM8776_FIELD_CTL(xname, reg, shift, initval, min, max, mask, flags) \
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = xname, \
+       .private_value = (initval) | ((min) << 8) | ((max) << 12) | \
+       ((mask) << 16) | ((shift) << 20) | ((reg) << 24) | (flags)
+#define WM8776_FIELD_CTL_ENUM(xname, reg, shift, init, min, max, mask, flags) {\
+       _WM8776_FIELD_CTL(xname " Capture Enum", \
+                         reg, shift, init, min, max, mask, flags), \
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
+                 SNDRV_CTL_ELEM_ACCESS_INACTIVE, \
+       .info = wm8776_field_enum_info, \
+       .get = wm8776_field_enum_get, \
+       .put = wm8776_field_enum_put, \
+}
+#define WM8776_FIELD_CTL_VOLUME(a, b, c, d, e, f, g, h, tlv_p) { \
+       _WM8776_FIELD_CTL(a " Capture Volume", b, c, d, e, f, g, h), \
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
+                 SNDRV_CTL_ELEM_ACCESS_INACTIVE | \
+                 SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
+       .info = wm8776_field_volume_info, \
+       .get = wm8776_field_volume_get, \
+       .put = wm8776_field_volume_put, \
+       .tlv = { .p = tlv_p }, \
+}
+
+static const DECLARE_TLV_DB_SCALE(wm87x6_dac_db_scale, -6000, 50, 0);
+static const DECLARE_TLV_DB_SCALE(wm8776_adc_db_scale, -2100, 50, 0);
+static const DECLARE_TLV_DB_SCALE(wm8776_hp_db_scale, -6000, 100, 0);
+static const DECLARE_TLV_DB_SCALE(wm8776_lct_db_scale, -1600, 100, 0);
+static const DECLARE_TLV_DB_SCALE(wm8776_maxgain_db_scale, 0, 400, 0);
+static const DECLARE_TLV_DB_SCALE(wm8776_ngth_db_scale, -7800, 600, 0);
+static const DECLARE_TLV_DB_SCALE(wm8776_maxatten_lim_db_scale, -1200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(wm8776_maxatten_alc_db_scale, -2100, 400, 0);
+
+static const struct snd_kcontrol_new ds_controls[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Headphone Playback Volume",
+               .info = wm8776_hp_vol_info,
+               .get = wm8776_hp_vol_get,
+               .put = wm8776_hp_vol_put,
+               .tlv = { .p = wm8776_hp_db_scale },
+       },
+       WM8776_BIT_SWITCH("Headphone Playback Switch",
+                         WM8776_PWRDOWN, WM8776_HPPD, 1, 0),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Input Capture Volume",
+               .info = wm8776_input_vol_info,
+               .get = wm8776_input_vol_get,
+               .put = wm8776_input_vol_put,
+               .tlv = { .p = wm8776_adc_db_scale },
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Line Capture Switch",
+               .info = snd_ctl_boolean_mono_info,
+               .get = wm8776_input_mux_get,
+               .put = wm8776_input_mux_put,
+               .private_value = 1 << 0,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Mic Capture Switch",
+               .info = snd_ctl_boolean_mono_info,
+               .get = wm8776_input_mux_get,
+               .put = wm8776_input_mux_put,
+               .private_value = 1 << 1,
+       },
+       WM8776_BIT_SWITCH("Aux", WM8776_ADCMUX, 1 << 2, 0, 0),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "ADC Filter Capture Enum",
+               .info = hpf_info,
+               .get = hpf_get,
+               .put = hpf_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Level Control Capture Enum",
+               .info = wm8776_level_control_info,
+               .get = wm8776_level_control_get,
+               .put = wm8776_level_control_put,
+               .private_value = 0,
+       },
+};
+static const struct snd_kcontrol_new lc_controls[] = {
+       WM8776_FIELD_CTL_VOLUME("Limiter Threshold",
+                               WM8776_ALCCTRL1, 0, 11, 0, 15, 0xf,
+                               LC_CONTROL_LIMITER, wm8776_lct_db_scale),
+       WM8776_FIELD_CTL_ENUM("Limiter Attack Time",
+                             WM8776_ALCCTRL3, 0, 2, 0, 10, 0xf,
+                             LC_CONTROL_LIMITER),
+       WM8776_FIELD_CTL_ENUM("Limiter Decay Time",
+                             WM8776_ALCCTRL3, 4, 3, 0, 10, 0xf,
+                             LC_CONTROL_LIMITER),
+       WM8776_FIELD_CTL_ENUM("Limiter Transient Window",
+                             WM8776_LIMITER, 4, 2, 0, 7, 0x7,
+                             LC_CONTROL_LIMITER),
+       WM8776_FIELD_CTL_VOLUME("Limiter Maximum Attenuation",
+                               WM8776_LIMITER, 0, 6, 3, 12, 0xf,
+                               LC_CONTROL_LIMITER,
+                               wm8776_maxatten_lim_db_scale),
+       WM8776_FIELD_CTL_VOLUME("ALC Target Level",
+                               WM8776_ALCCTRL1, 0, 11, 0, 15, 0xf,
+                               LC_CONTROL_ALC, wm8776_lct_db_scale),
+       WM8776_FIELD_CTL_ENUM("ALC Attack Time",
+                             WM8776_ALCCTRL3, 0, 2, 0, 10, 0xf,
+                             LC_CONTROL_ALC),
+       WM8776_FIELD_CTL_ENUM("ALC Decay Time",
+                             WM8776_ALCCTRL3, 4, 3, 0, 10, 0xf,
+                             LC_CONTROL_ALC),
+       WM8776_FIELD_CTL_VOLUME("ALC Maximum Gain",
+                               WM8776_ALCCTRL1, 4, 7, 1, 7, 0x7,
+                               LC_CONTROL_ALC, wm8776_maxgain_db_scale),
+       WM8776_FIELD_CTL_VOLUME("ALC Maximum Attenuation",
+                               WM8776_LIMITER, 0, 10, 10, 15, 0xf,
+                               LC_CONTROL_ALC, wm8776_maxatten_alc_db_scale),
+       WM8776_FIELD_CTL_ENUM("ALC Hold Time",
+                             WM8776_ALCCTRL2, 0, 0, 0, 15, 0xf,
+                             LC_CONTROL_ALC),
+       WM8776_BIT_SWITCH("Noise Gate Capture Switch",
+                         WM8776_NOISEGATE, WM8776_NGAT, 0,
+                         LC_CONTROL_ALC),
+       WM8776_FIELD_CTL_VOLUME("Noise Gate Threshold",
+                               WM8776_NOISEGATE, 2, 0, 0, 7, 0x7,
+                               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;
+       unsigned int i;
+       struct snd_kcontrol *ctl;
+       int err;
+
+       for (i = 0; i < ARRAY_SIZE(ds_controls); ++i) {
+               ctl = snd_ctl_new1(&ds_controls[i], chip);
+               if (!ctl)
+                       return -ENOMEM;
+               err = snd_ctl_add(chip->card, ctl);
+               if (err < 0)
+                       return err;
+       }
+       BUILD_BUG_ON(ARRAY_SIZE(lc_controls) != ARRAY_SIZE(data->lc_controls));
+       for (i = 0; i < ARRAY_SIZE(lc_controls); ++i) {
+               ctl = snd_ctl_new1(&lc_controls[i], chip);
+               if (!ctl)
+                       return -ENOMEM;
+               err = snd_ctl_add(chip->card, ctl);
+               if (err < 0)
+                       return err;
+               data->lc_controls[i] = ctl;
+       }
+       return 0;
+}
+
+static const struct oxygen_model model_xonar_ds = {
+       .shortname = "Xonar DS",
+       .longname = "Asus Virtuoso 200",
+       .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,
+       .resume = xonar_ds_resume,
+       .pcm_hardware_filter = wm8776_adc_hardware_filter,
+       .get_i2s_mclk = oxygen_default_i2s_mclk,
+       .set_dac_params = set_wm87x6_dac_params,
+       .set_adc_params = set_wm8776_adc_params,
+       .update_dac_volume = update_wm87x6_volume,
+       .update_dac_mute = update_wm87x6_mute,
+       .gpio_changed = xonar_ds_gpio_changed,
+       .dac_tlv = wm87x6_dac_db_scale,
+       .model_data_size = sizeof(struct xonar_wm87x6),
+       .device_config = PLAYBACK_0_TO_I2S |
+                        PLAYBACK_1_TO_SPDIF |
+                        CAPTURE_0_FROM_I2S_1,
+       .dac_channels = 8,
+       .dac_volume_min = 255 - 2*60,
+       .dac_volume_max = 255,
+       .function_flags = OXYGEN_FUNCTION_SPI,
+       .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+       .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+};
+
+int __devinit get_xonar_wm87x6_model(struct oxygen *chip,
+                                    const struct pci_device_id *id)
+{
+       switch (id->subdevice) {
+       case 0x838e:
+               chip->model = model_xonar_ds;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
index 833e9c7b27c7bce4b66d52b7a45ca1455ca6f912..95cfde27d25c6da928c5f02dc211e4231fd840cb 100644 (file)
@@ -94,7 +94,7 @@ enum {
        PCI_ID_LAST
 };
 
-static struct pci_device_id pcxhr_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(pcxhr_ids) = {
        { 0x10b5, 0x9656, 0x1369, 0xb001, 0, 0, PCI_ID_VX882HR, },
        { 0x10b5, 0x9656, 0x1369, 0xb101, 0, 0, PCI_ID_PCX882HR, },
        { 0x10b5, 0x9656, 0x1369, 0xb201, 0, 0, PCI_ID_VX881HR, },
index e66ef2b69b5d45a7424a161f6e90767628d98402..960a227eb6531795bbbdbdfa8430238939079a5c 100644 (file)
@@ -506,7 +506,7 @@ static int riptide_reset(struct cmdif *cif, struct snd_riptide *chip);
 /*
  */
 
-static struct pci_device_id snd_riptide_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_riptide_ids) = {
        { PCI_DEVICE(0x127a, 0x4310) },
        { PCI_DEVICE(0x127a, 0x4320) },
        { PCI_DEVICE(0x127a, 0x4330) },
@@ -515,7 +515,7 @@ static struct pci_device_id snd_riptide_ids[] = {
 };
 
 #ifdef SUPPORT_JOYSTICK
-static struct pci_device_id snd_riptide_joystick_ids[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(snd_riptide_joystick_ids) = {
        { PCI_DEVICE(0x127a, 0x4312) },
        { PCI_DEVICE(0x127a, 0x4322) },
        { PCI_DEVICE(0x127a, 0x4332) },
index f977dba7cbd09462ac760219711c04dbb189ea0e..d5e1c6eb7b7bba56f7a57e4b34229290d466a529 100644 (file)
@@ -226,7 +226,7 @@ struct rme32 {
        struct snd_kcontrol *spdif_ctl;
 };
 
-static struct pci_device_id snd_rme32_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_rme32_ids) = {
        {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32), 0,},
        {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_8), 0,},
        {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_PRO), 0,},
index 2ba5c0fd55dbb7adc590e568e0b78350124ffd91..9d5252bc870c15e2d86a4558a5ffb24124eda574 100644 (file)
@@ -231,7 +231,7 @@ struct rme96 {
        struct snd_kcontrol   *spdif_ctl;
 };
 
-static struct pci_device_id snd_rme96_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_rme96_ids) = {
        { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96), 0, },
        { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8), 0, },
        { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8_PRO), 0, },
index 7bb827c7d8061bfea72e0c2579015f8668bbebc9..52c6eb57cc3f51fafa7f39c165543e046dd52016 100644 (file)
@@ -585,7 +585,7 @@ static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_d
 }
 
 
-static struct pci_device_id snd_hdsp_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_hdsp_ids) = {
        {
                .vendor = PCI_VENDOR_ID_XILINX,
                .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP,
index a1b10d1a384d3950c7631d6b1f59fa7b879f896a..3d72c1effeef7937e70ba72f2f01be235c8c0a0a 100644 (file)
@@ -512,7 +512,7 @@ static char channel_map_madi_ss[HDSPM_MAX_CHANNELS] = {
 };
 
 
-static struct pci_device_id snd_hdspm_ids[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(snd_hdspm_ids) = {
        {
         .vendor = PCI_VENDOR_ID_XILINX,
         .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI,
index bc539abb210582c01797a4115916e00088f3be92..44a3e2d8c5563e757fe437c569a45658ce471b41 100644 (file)
@@ -314,7 +314,7 @@ static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_d
 }
 
 
-static struct pci_device_id snd_rme9652_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_rme9652_ids) = {
        {
                .vendor    = 0x10ee,
                .device    = 0x3fc4,
index 1a5ff06110725ef407e1d82f83b05ceddfc70b01..7e3e8fbc90fefca268bde1a8ec27361b8889ac78 100644 (file)
@@ -48,7 +48,7 @@ MODULE_PARM_DESC(id, "ID string for SiS7019 Audio Accelerator.");
 module_param(enable, bool, 0444);
 MODULE_PARM_DESC(enable, "Enable SiS7019 Audio Accelerator.");
 
-static struct pci_device_id snd_sis7019_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_sis7019_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x7019) },
        { 0, }
 };
index 1f6406c4534d455120efcdd0c1c6e9e3b98a9173..337b9facadfdb4f1afc9061f857cf78c37c8703c 100644 (file)
@@ -242,7 +242,7 @@ struct sonicvibes {
 #endif
 };
 
-static struct pci_device_id snd_sonic_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_sonic_ids) = {
        { PCI_VDEVICE(S3, 0xca00), 0, },
         { 0, }
 };
index 21cef97d478dc8fb0a127d73453714d886facedf..6d0581841d7a3536baebd40f7c47ee7b80ecaaff 100644 (file)
@@ -62,7 +62,7 @@ MODULE_PARM_DESC(pcm_channels, "Number of hardware channels assigned for PCM.");
 module_param_array(wavetable_size, int, NULL, 0444);
 MODULE_PARM_DESC(wavetable_size, "Maximum memory size in kB for wavetable synth.");
 
-static struct pci_device_id snd_trident_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_trident_ids) = {
        {PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX), 
                PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0},
        {PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX), 
index 8a332d2f615cfc01e4612a9eb459628e8596c59b..7e494b6a1d0e4b63ce6171dbe82d3efa75ce024e 100644 (file)
@@ -401,7 +401,7 @@ struct via82xx {
 #endif
 };
 
-static struct pci_device_id snd_via82xx_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_via82xx_ids) = {
        /* 0x1106, 0x3058 */
        { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C686_5), TYPE_CARD_VIA686, },    /* 686A */
        /* 0x1106, 0x3059 */
@@ -1790,6 +1790,12 @@ static struct ac97_quirk ac97_quirks[] = {
                .name = "ASRock K7VT2",
                .type = AC97_TUNE_HP_ONLY
        },
+       {
+               .subvendor = 0x110a,
+               .subdevice = 0x0079,
+               .name = "Fujitsu Siemens D1289",
+               .type = AC97_TUNE_HP_ONLY
+       },
        {
                .subvendor = 0x1019,
                .subdevice = 0x0a81,
index 47eb61561dfcad83b0bd7c22fe91f5ef9519856e..f7e8bbbe395392bbb4eecd170f75cfa5a3bd68c9 100644 (file)
@@ -260,7 +260,7 @@ struct via82xx_modem {
        struct snd_info_entry *proc_entry;
 };
 
-static struct pci_device_id snd_via82xx_modem_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_via82xx_modem_ids) = {
        { PCI_VDEVICE(VIA, 0x3068), TYPE_CARD_VIA82XX_MODEM, },
        { 0, }
 };
index fc9136c3e0d7824a67d88d4bbc5781e4b7ac375d..99a9a814be0beecbb71d98df7a328652694e7ce2 100644 (file)
@@ -60,7 +60,7 @@ enum {
        VX_PCI_VX222_NEW
 };
 
-static struct pci_device_id snd_vx222_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_vx222_ids) = {
        { 0x10b5, 0x9050, 0x1369, PCI_ANY_ID, 0, 0, VX_PCI_VX222_OLD, },   /* PLX */
        { 0x10b5, 0x9030, 0x1369, PCI_ANY_ID, 0, 0, VX_PCI_VX222_NEW, },   /* PLX */
        { 0, }
index e6b18b90d4510afa4393d700110cc84200c2f5ef..80c6821133816978cb91c92e8391e463d7156e48 100644 (file)
@@ -66,7 +66,7 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address");
 module_param_array(rear_switch, bool, NULL, 0444);
 MODULE_PARM_DESC(rear_switch, "Enable shared rear/line-in switch");
 
-static struct pci_device_id snd_ymfpci_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_ymfpci_ids) = {
        { PCI_VDEVICE(YAMAHA, 0x0004), 0, },   /* YMF724 */
        { PCI_VDEVICE(YAMAHA, 0x000d), 0, },   /* YMF724F */
        { PCI_VDEVICE(YAMAHA, 0x000a), 0, },   /* YMF740 */
index 5cfa608823f78d65e3f80d9e6b9ff08e377acb31..0d668f471620cc81283142cc16cc0d1159cb84f9 100644 (file)
  */
 
 #include <linux/slab.h>
-#include <linux/vmalloc.h>
 #include <linux/delay.h>
 #include <sound/core.h>
 #include <sound/asoundef.h>
 #include "pdaudiocf.h"
 
 
-/*
- * we use a vmalloc'ed (sg-)buffer
- */
-
-/* get the physical page pointer on the given offset */
-static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, unsigned long offset)
-{
-       void *pageptr = subs->runtime->dma_area + offset;
-       return vmalloc_to_page(pageptr);
-}
-
-/*
- * hw_params callback
- * NOTE: this may be called not only once per pcm open!
- */
-static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t size)
-{
-       struct snd_pcm_runtime *runtime = subs->runtime;
-       if (runtime->dma_area) {
-               if (runtime->dma_bytes >= size)
-                       return 0; /* already enough large */
-               vfree(runtime->dma_area);
-       }
-       runtime->dma_area = vmalloc_32_user(size);
-       if (! runtime->dma_area)
-               return -ENOMEM;
-       runtime->dma_bytes = size;
-       return 0;
-}
-
-/*
- * hw_free callback
- * NOTE: this may be called not only once per pcm open!
- */
-static int snd_pcm_free_vmalloc_buffer(struct snd_pcm_substream *subs)
-{
-       struct snd_pcm_runtime *runtime = subs->runtime;
-
-       vfree(runtime->dma_area);
-       runtime->dma_area = NULL;
-       return 0;
-}
-
 /*
  * clear the SRAM contents
  */
@@ -147,7 +103,8 @@ static int pdacf_pcm_trigger(struct snd_pcm_substream *subs, int cmd)
 static int pdacf_pcm_hw_params(struct snd_pcm_substream *subs,
                                     struct snd_pcm_hw_params *hw_params)
 {
-       return snd_pcm_alloc_vmalloc_buffer(subs, params_buffer_bytes(hw_params));
+       return snd_pcm_lib_alloc_vmalloc_32_buffer
+                                       (subs, params_buffer_bytes(hw_params));
 }
 
 /*
@@ -155,7 +112,7 @@ static int pdacf_pcm_hw_params(struct snd_pcm_substream *subs,
  */
 static int pdacf_pcm_hw_free(struct snd_pcm_substream *subs)
 {
-       return snd_pcm_free_vmalloc_buffer(subs);
+       return snd_pcm_lib_free_vmalloc_buffer(subs);
 }
 
 /*
@@ -319,7 +276,8 @@ static struct snd_pcm_ops pdacf_pcm_capture_ops = {
        .prepare =      pdacf_pcm_prepare,
        .trigger =      pdacf_pcm_trigger,
        .pointer =      pdacf_pcm_capture_pointer,
-       .page =         snd_pcm_get_vmalloc_page,
+       .page =         snd_pcm_lib_get_vmalloc_page,
+       .mmap =         snd_pcm_lib_mmap_vmalloc,
 };
 
 
index cf0dfb7ca22146baba398d3f9d0c70a3e1b4ce22..67cbfe7283da1c481cbaafad4c731de17b670a76 100644 (file)
@@ -349,9 +349,7 @@ static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
                        sport_handle->tx_dma_buf = dma_alloc_coherent(NULL, \
                                size, &sport_handle->tx_dma_phy, GFP_KERNEL);
                        if (!sport_handle->tx_dma_buf) {
-                               pr_err("Failed to allocate memory for tx dma \
-                                       buf - Please increase uncached DMA \
-                                       memory region\n");
+                               pr_err("Failed to allocate memory for tx dma buf - Please increase uncached DMA memory region\n");
                                return -ENOMEM;
                        } else
                                memset(sport_handle->tx_dma_buf, 0, size);
@@ -362,9 +360,7 @@ static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
                        sport_handle->rx_dma_buf = dma_alloc_coherent(NULL, \
                                size, &sport_handle->rx_dma_phy, GFP_KERNEL);
                        if (!sport_handle->rx_dma_buf) {
-                               pr_err("Failed to allocate memory for rx dma \
-                                       buf - Please increase uncached DMA \
-                                       memory region\n");
+                               pr_err("Failed to allocate memory for rx dma buf - Please increase uncached DMA memory region\n");
                                return -ENOMEM;
                        } else
                                memset(sport_handle->rx_dma_buf, 0, size);
index 62fbb8459569a6d78690bbf7b100a3aa47ea745a..c6c6a4a7d948feb34402bd0d332d84f738a529bd 100644 (file)
@@ -207,8 +207,7 @@ static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
        buf->area = dma_alloc_coherent(pcm->card->dev, size,
                        &buf->addr, GFP_KERNEL);
        if (!buf->area) {
-               pr_err("Failed to allocate dma memory \
-                       Please increase uncached DMA memory region\n");
+               pr_err("Failed to allocate dma memory - Please increase uncached DMA memory region\n");
                return -ENOMEM;
        }
        buf->bytes = size;
index a8c73cbbd68512198e47b25f478aba52496dc6d1..5e03bb2f3cd7db4ddc9f72337709b4f56d07c8a4 100644 (file)
@@ -244,8 +244,7 @@ static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
        buf->area = dma_alloc_coherent(pcm->card->dev, size * 4,
                &buf->addr, GFP_KERNEL);
        if (!buf->area) {
-               pr_err("Failed to allocate dma memory \
-                       Please increase uncached DMA memory region\n");
+               pr_err("Failed to allocate dma memory - Please increase uncached DMA memory region\n");
                return -ENOMEM;
        }
        buf->bytes = size;
index 52b005f8fed413ca052c2e1bc3dca9e7155c6ea2..1743d565e996d937c3e368a2c1d276ef5f61da77 100644 (file)
@@ -23,6 +23,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_AK4671 if I2C
        select SND_SOC_CS4270 if I2C
        select SND_SOC_MAX9877 if I2C
+       select SND_SOC_DA7210 if I2C
        select SND_SOC_PCM3008
        select SND_SOC_SPDIF
        select SND_SOC_SSM2602 if I2C
@@ -35,6 +36,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_TWL4030 if TWL4030_CORE
        select SND_SOC_UDA134X
        select SND_SOC_UDA1380 if I2C
+       select SND_SOC_WM2000 if I2C
        select SND_SOC_WM8350 if MFD_WM8350
        select SND_SOC_WM8400 if MFD_WM8400
        select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI
@@ -49,14 +51,18 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8900 if I2C
        select SND_SOC_WM8903 if I2C
+       select SND_SOC_WM8904 if I2C
        select SND_SOC_WM8940 if I2C
+       select SND_SOC_WM8955 if I2C
        select SND_SOC_WM8960 if I2C
        select SND_SOC_WM8961 if I2C
        select SND_SOC_WM8971 if I2C
        select SND_SOC_WM8974 if I2C
+       select SND_SOC_WM8978 if I2C
        select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8990 if I2C
        select SND_SOC_WM8993 if I2C
+       select SND_SOC_WM8994 if MFD_WM8994
        select SND_SOC_WM9081 if I2C
        select SND_SOC_WM9705 if SND_SOC_AC97_BUS
        select SND_SOC_WM9712 if SND_SOC_AC97_BUS
@@ -112,6 +118,9 @@ config SND_SOC_AK4671
 config SND_SOC_CS4270
        tristate
 
+config SND_SOC_DA7210
+        tristate
+
 # Cirrus Logic CS4270 Codec VD = 3.3V Errata
 # Select if you are affected by the errata where the part will not function
 # if MCLK divide-by-1.5 is selected and VD is set to 3.3V.  The driver will
@@ -203,9 +212,15 @@ config SND_SOC_WM8900
 config SND_SOC_WM8903
        tristate
 
+config SND_SOC_WM8904
+       tristate
+
 config SND_SOC_WM8940
         tristate
 
+config SND_SOC_WM8955
+       tristate
+
 config SND_SOC_WM8960
        tristate
 
@@ -218,6 +233,9 @@ config SND_SOC_WM8971
 config SND_SOC_WM8974
        tristate
 
+config SND_SOC_WM8978
+       tristate
+
 config SND_SOC_WM8988
        tristate
 
@@ -227,6 +245,9 @@ config SND_SOC_WM8990
 config SND_SOC_WM8993
        tristate
 
+config SND_SOC_WM8994
+       tristate
+
 config SND_SOC_WM9081
        tristate
 
@@ -245,3 +266,6 @@ config SND_SOC_MAX9877
 
 config SND_SOC_TPA6130A2
        tristate
+
+config SND_SOC_WM2000
+       tristate
index dbaecb133ac72da0331e66cd7c33d5605d370862..dd5ce6df6292c7b3c01d197bdf01fa44367f3370 100644 (file)
@@ -10,6 +10,7 @@ snd-soc-ak4642-objs := ak4642.o
 snd-soc-ak4671-objs := ak4671.o
 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-pcm3008-objs := pcm3008.o
 snd-soc-spdif-objs := spdif_transciever.o
@@ -36,14 +37,18 @@ snd-soc-wm8753-objs := wm8753.o
 snd-soc-wm8776-objs := wm8776.o
 snd-soc-wm8900-objs := wm8900.o
 snd-soc-wm8903-objs := wm8903.o
+snd-soc-wm8904-objs := wm8904.o
 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-wm8971-objs := wm8971.o
 snd-soc-wm8974-objs := wm8974.o
+snd-soc-wm8978-objs := wm8978.o
 snd-soc-wm8988-objs := wm8988.o
 snd-soc-wm8990-objs := wm8990.o
 snd-soc-wm8993-objs := wm8993.o
+snd-soc-wm8994-objs := wm8994.o
 snd-soc-wm9081-objs := wm9081.o
 snd-soc-wm9705-objs := wm9705.o
 snd-soc-wm9712-objs := wm9712.o
@@ -53,6 +58,7 @@ snd-soc-wm-hubs-objs := wm_hubs.o
 # Amp
 snd-soc-max9877-objs := max9877.o
 snd-soc-tpa6130a2-objs := tpa6130a2.o
+snd-soc-wm2000-objs := wm2000.o
 
 obj-$(CONFIG_SND_SOC_AC97_CODEC)       += snd-soc-ac97.o
 obj-$(CONFIG_SND_SOC_AD1836)   += snd-soc-ad1836.o
@@ -66,6 +72,7 @@ obj-$(CONFIG_SND_SOC_AK4642)  += snd-soc-ak4642.o
 obj-$(CONFIG_SND_SOC_AK4671)   += snd-soc-ak4671.o
 obj-$(CONFIG_SND_SOC_CS4270)   += snd-soc-cs4270.o
 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_PCM3008)  += snd-soc-pcm3008.o
 obj-$(CONFIG_SND_SOC_SPDIF)    += snd-soc-spdif.o
@@ -92,14 +99,18 @@ obj-$(CONFIG_SND_SOC_WM8753)        += snd-soc-wm8753.o
 obj-$(CONFIG_SND_SOC_WM8776)   += snd-soc-wm8776.o
 obj-$(CONFIG_SND_SOC_WM8900)   += snd-soc-wm8900.o
 obj-$(CONFIG_SND_SOC_WM8903)   += snd-soc-wm8903.o
-obj-$(CONFIG_SND_SOC_WM8971)   += snd-soc-wm8971.o
-obj-$(CONFIG_SND_SOC_WM8974)   += snd-soc-wm8974.o
+obj-$(CONFIG_SND_SOC_WM8904)   += snd-soc-wm8904.o
 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_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_WM8988)   += snd-soc-wm8988.o
 obj-$(CONFIG_SND_SOC_WM8990)   += snd-soc-wm8990.o
 obj-$(CONFIG_SND_SOC_WM8993)   += snd-soc-wm8993.o
+obj-$(CONFIG_SND_SOC_WM8994)   += snd-soc-wm8994.o
 obj-$(CONFIG_SND_SOC_WM9081)   += snd-soc-wm9081.o
 obj-$(CONFIG_SND_SOC_WM9705)   += snd-soc-wm9705.o
 obj-$(CONFIG_SND_SOC_WM9712)   += snd-soc-wm9712.o
@@ -109,3 +120,4 @@ obj-$(CONFIG_SND_SOC_WM_HUBS)       += snd-soc-wm-hubs.o
 # Amp
 obj-$(CONFIG_SND_SOC_MAX9877)  += snd-soc-max9877.o
 obj-$(CONFIG_SND_SOC_TPA6130A2)        += snd-soc-tpa6130a2.o
+obj-$(CONFIG_SND_SOC_WM2000)   += snd-soc-wm2000.o
index 2c18e3d1b71e3aa993719f32c6a911ef9295d4f4..3c80137d59382198138af20ef2050338a6b9a73d 100644 (file)
@@ -171,57 +171,35 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-
-/*
- * interface to read/write ad1836 register
- */
-#define AD1836_SPI_REG_SHFT 12
-#define AD1836_SPI_READ     (1 << 11)
-#define AD1836_SPI_VAL_MSK  0x3FF
-
-/*
- * write to the ad1836 register space
- */
-
-static int ad1836_write_reg(struct snd_soc_codec *codec, unsigned int reg,
-               unsigned int value)
+#ifdef CONFIG_PM
+static int ad1836_soc_suspend(struct platform_device *pdev,
+               pm_message_t state)
 {
-       u16 *reg_cache = codec->reg_cache;
-       int ret = 0;
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->card->codec;
 
-       if (value != reg_cache[reg]) {
-               unsigned short buf;
-               struct spi_transfer t = {
-                       .tx_buf = &buf,
-                       .len = 2,
-               };
-               struct spi_message m;
-
-               buf = (reg << AD1836_SPI_REG_SHFT) |
-                       (value & AD1836_SPI_VAL_MSK);
-               spi_message_init(&m);
-               spi_message_add_tail(&t, &m);
-               ret = spi_sync(codec->control_data, &m);
-               if (ret == 0)
-                       reg_cache[reg] = value;
-       }
+       /* reset clock control mode */
+       u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2);
+       adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK;
 
-       return ret;
+       return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2);
 }
 
-/*
- * read from the ad1836 register space cache
- */
-static unsigned int ad1836_read_reg_cache(struct snd_soc_codec *codec,
-                                         unsigned int reg)
+static int ad1836_soc_resume(struct platform_device *pdev)
 {
-       u16 *reg_cache = codec->reg_cache;
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->card->codec;
 
-       if (reg >= codec->reg_cache_size)
-               return -EINVAL;
+       /* restore clock control mode */
+       u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2);
+       adc_ctrl2 |= AD1836_ADC_AUX;
 
-       return reg_cache[reg];
+       return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2);
 }
+#else
+#define ad1836_soc_suspend NULL
+#define ad1836_soc_resume  NULL
+#endif
 
 static int __devinit ad1836_spi_probe(struct spi_device *spi)
 {
@@ -306,32 +284,38 @@ static int ad1836_register(struct ad1836_priv *ad1836)
        codec->owner = THIS_MODULE;
        codec->dai = &ad1836_dai;
        codec->num_dai = 1;
-       codec->write = ad1836_write_reg;
-       codec->read = ad1836_read_reg_cache;
        INIT_LIST_HEAD(&codec->dapm_widgets);
        INIT_LIST_HEAD(&codec->dapm_paths);
 
        ad1836_dai.dev = codec->dev;
        ad1836_codec = codec;
 
+       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",
+                               ret);
+               kfree(ad1836);
+               return ret;
+       }
+
        /* default setting for ad1836 */
        /* de-emphasis: 48kHz, power-on dac */
-       codec->write(codec, AD1836_DAC_CTRL1, 0x300);
+       snd_soc_write(codec, AD1836_DAC_CTRL1, 0x300);
        /* unmute dac channels */
-       codec->write(codec, AD1836_DAC_CTRL2, 0x0);
+       snd_soc_write(codec, AD1836_DAC_CTRL2, 0x0);
        /* high-pass filter enable, power-on adc */
-       codec->write(codec, AD1836_ADC_CTRL1, 0x100);
+       snd_soc_write(codec, AD1836_ADC_CTRL1, 0x100);
        /* unmute adc channles, adc aux mode */
-       codec->write(codec, AD1836_ADC_CTRL2, 0x180);
+       snd_soc_write(codec, AD1836_ADC_CTRL2, 0x180);
        /* left/right diff:PGA/MUX */
-       codec->write(codec, AD1836_ADC_CTRL3, 0x3A);
+       snd_soc_write(codec, AD1836_ADC_CTRL3, 0x3A);
        /* volume */
-       codec->write(codec, AD1836_DAC_L1_VOL, 0x3FF);
-       codec->write(codec, AD1836_DAC_R1_VOL, 0x3FF);
-       codec->write(codec, AD1836_DAC_L2_VOL, 0x3FF);
-       codec->write(codec, AD1836_DAC_R2_VOL, 0x3FF);
-       codec->write(codec, AD1836_DAC_L3_VOL, 0x3FF);
-       codec->write(codec, AD1836_DAC_R3_VOL, 0x3FF);
+       snd_soc_write(codec, AD1836_DAC_L1_VOL, 0x3FF);
+       snd_soc_write(codec, AD1836_DAC_R1_VOL, 0x3FF);
+       snd_soc_write(codec, AD1836_DAC_L2_VOL, 0x3FF);
+       snd_soc_write(codec, AD1836_DAC_R2_VOL, 0x3FF);
+       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) {
@@ -404,6 +388,8 @@ static int ad1836_remove(struct platform_device *pdev)
 struct snd_soc_codec_device soc_codec_dev_ad1836 = {
        .probe =        ad1836_probe,
        .remove =       ad1836_remove,
+       .suspend =      ad1836_soc_suspend,
+       .resume =       ad1836_soc_resume,
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_ad1836);
 
index 7660ee6973c0644567386c9d016d6bed7d0f1b79..e9d90d3951c520f4c18fdb56d9eae6d72dd0b160 100644 (file)
@@ -54,6 +54,7 @@
 #define AD1836_ADC_SERFMT_MASK        (7 << 6)
 #define AD1836_ADC_SERFMT_PCK256       (0x4 << 6)
 #define AD1836_ADC_SERFMT_PCK128       (0x5 << 6)
+#define AD1836_ADC_AUX                 (0x6 << 6)
 
 #define AD1836_ADC_CTRL3               14
 
index 5d489186c05bb036d5a98aa2bbaa4b0537ad38df..c233810d463df1c4e50c866dd277b94d3b9bd81a 100644 (file)
@@ -46,6 +46,11 @@ struct ad1938_priv {
        u8 reg_cache[AD1938_NUM_REGS];
 };
 
+/* ad1938 register cache & default register settings */
+static const u8 ad1938_reg[AD1938_NUM_REGS] = {
+       0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0,
+};
+
 static struct snd_soc_codec *ad1938_codec;
 struct snd_soc_codec_device soc_codec_dev_ad1938;
 static int ad1938_register(struct ad1938_priv *ad1938);
@@ -97,6 +102,7 @@ static const struct snd_kcontrol_new ad1938_snd_controls[] = {
 static const struct snd_soc_dapm_widget ad1938_dapm_widgets[] = {
        SND_SOC_DAPM_DAC("DAC", "Playback", AD1938_DAC_CTRL0, 0, 1),
        SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_SUPPLY("PLL_PWR", AD1938_PLL_CLK_CTRL0, 0, 1, NULL, 0),
        SND_SOC_DAPM_SUPPLY("ADC_PWR", AD1938_ADC_CTRL0, 0, 1, NULL, 0),
        SND_SOC_DAPM_OUTPUT("DAC1OUT"),
        SND_SOC_DAPM_OUTPUT("DAC2OUT"),
@@ -107,6 +113,8 @@ static const struct snd_soc_dapm_widget ad1938_dapm_widgets[] = {
 };
 
 static const struct snd_soc_dapm_route audio_paths[] = {
+       { "DAC", NULL, "PLL_PWR" },
+       { "ADC", NULL, "PLL_PWR" },
        { "DAC", NULL, "ADC_PWR" },
        { "ADC", NULL, "ADC_PWR" },
        { "DAC1OUT", "DAC1 Switch", "DAC" },
@@ -126,30 +134,20 @@ static int ad1938_mute(struct snd_soc_dai *dai, int mute)
        struct snd_soc_codec *codec = dai->codec;
        int reg;
 
-       reg = codec->read(codec, AD1938_DAC_CTRL2);
+       reg = snd_soc_read(codec, AD1938_DAC_CTRL2);
        reg = (mute > 0) ? reg | AD1938_DAC_MASTER_MUTE : reg &
                (~AD1938_DAC_MASTER_MUTE);
-       codec->write(codec, AD1938_DAC_CTRL2, reg);
-
-       return 0;
-}
-
-static inline int ad1938_pll_powerctrl(struct snd_soc_codec *codec, int cmd)
-{
-       int reg = codec->read(codec, AD1938_PLL_CLK_CTRL0);
-       reg = (cmd > 0) ? reg & (~AD1938_PLL_POWERDOWN) : reg |
-               AD1938_PLL_POWERDOWN;
-       codec->write(codec, AD1938_PLL_CLK_CTRL0, reg);
+       snd_soc_write(codec, AD1938_DAC_CTRL2, reg);
 
        return 0;
 }
 
 static int ad1938_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
-                              unsigned int mask, int slots, int width)
+                              unsigned int rx_mask, int slots, int width)
 {
        struct snd_soc_codec *codec = dai->codec;
-       int dac_reg = codec->read(codec, AD1938_DAC_CTRL1);
-       int adc_reg = codec->read(codec, AD1938_ADC_CTRL2);
+       int dac_reg = snd_soc_read(codec, AD1938_DAC_CTRL1);
+       int adc_reg = snd_soc_read(codec, AD1938_ADC_CTRL2);
 
        dac_reg &= ~AD1938_DAC_CHAN_MASK;
        adc_reg &= ~AD1938_ADC_CHAN_MASK;
@@ -175,8 +173,8 @@ static int ad1938_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
                return -EINVAL;
        }
 
-       codec->write(codec, AD1938_DAC_CTRL1, dac_reg);
-       codec->write(codec, AD1938_ADC_CTRL2, adc_reg);
+       snd_soc_write(codec, AD1938_DAC_CTRL1, dac_reg);
+       snd_soc_write(codec, AD1938_ADC_CTRL2, adc_reg);
 
        return 0;
 }
@@ -187,8 +185,8 @@ static int ad1938_set_dai_fmt(struct snd_soc_dai *codec_dai,
        struct snd_soc_codec *codec = codec_dai->codec;
        int adc_reg, dac_reg;
 
-       adc_reg = codec->read(codec, AD1938_ADC_CTRL2);
-       dac_reg = codec->read(codec, AD1938_DAC_CTRL1);
+       adc_reg = snd_soc_read(codec, AD1938_ADC_CTRL2);
+       dac_reg = snd_soc_read(codec, AD1938_DAC_CTRL1);
 
        /* At present, the driver only support AUX ADC mode(SND_SOC_DAIFMT_I2S
         * with TDM) and ADC&DAC TDM mode(SND_SOC_DAIFMT_DSP_A)
@@ -265,8 +263,8 @@ static int ad1938_set_dai_fmt(struct snd_soc_dai *codec_dai,
                return -EINVAL;
        }
 
-       codec->write(codec, AD1938_ADC_CTRL2, adc_reg);
-       codec->write(codec, AD1938_DAC_CTRL1, dac_reg);
+       snd_soc_write(codec, AD1938_ADC_CTRL2, adc_reg);
+       snd_soc_write(codec, AD1938_DAC_CTRL1, dac_reg);
 
        return 0;
 }
@@ -295,134 +293,13 @@ static int ad1938_hw_params(struct snd_pcm_substream *substream,
                break;
        }
 
-       reg = codec->read(codec, AD1938_DAC_CTRL2);
+       reg = snd_soc_read(codec, AD1938_DAC_CTRL2);
        reg = (reg & (~AD1938_DAC_WORD_LEN_MASK)) | word_len;
-       codec->write(codec, AD1938_DAC_CTRL2, reg);
+       snd_soc_write(codec, AD1938_DAC_CTRL2, reg);
 
-       reg = codec->read(codec, AD1938_ADC_CTRL1);
+       reg = snd_soc_read(codec, AD1938_ADC_CTRL1);
        reg = (reg & (~AD1938_ADC_WORD_LEN_MASK)) | word_len;
-       codec->write(codec, AD1938_ADC_CTRL1, reg);
-
-       return 0;
-}
-
-static int ad1938_set_bias_level(struct snd_soc_codec *codec,
-               enum snd_soc_bias_level level)
-{
-       switch (level) {
-       case SND_SOC_BIAS_ON:
-               ad1938_pll_powerctrl(codec, 1);
-               break;
-       case SND_SOC_BIAS_PREPARE:
-               break;
-       case SND_SOC_BIAS_STANDBY:
-       case SND_SOC_BIAS_OFF:
-               ad1938_pll_powerctrl(codec, 0);
-               break;
-       }
-       codec->bias_level = level;
-       return 0;
-}
-
-/*
- * interface to read/write ad1938 register
- */
-
-#define AD1938_SPI_ADDR    0x4
-#define AD1938_SPI_READ    0x1
-#define AD1938_SPI_BUFLEN  3
-
-/*
- * write to the ad1938 register space
- */
-
-static int ad1938_write_reg(struct snd_soc_codec *codec, unsigned int reg,
-               unsigned int value)
-{
-       u8 *reg_cache = codec->reg_cache;
-       int ret = 0;
-
-       if (value != reg_cache[reg]) {
-               uint8_t buf[AD1938_SPI_BUFLEN];
-               struct spi_transfer t = {
-                       .tx_buf = buf,
-                       .len = AD1938_SPI_BUFLEN,
-               };
-               struct spi_message m;
-
-               buf[0] = AD1938_SPI_ADDR << 1;
-               buf[1] = reg;
-               buf[2] = value;
-               spi_message_init(&m);
-               spi_message_add_tail(&t, &m);
-               ret = spi_sync(codec->control_data, &m);
-               if (ret == 0)
-                       reg_cache[reg] = value;
-       }
-
-       return ret;
-}
-
-/*
- * read from the ad1938 register space cache
- */
-
-static unsigned int ad1938_read_reg_cache(struct snd_soc_codec *codec,
-                                         unsigned int reg)
-{
-       u8 *reg_cache = codec->reg_cache;
-
-       if (reg >= codec->reg_cache_size)
-               return -EINVAL;
-
-       return reg_cache[reg];
-}
-
-/*
- * read from the ad1938 register space
- */
-
-static unsigned int ad1938_read_reg(struct snd_soc_codec *codec,
-                                               unsigned int reg)
-{
-       char w_buf[AD1938_SPI_BUFLEN];
-       char r_buf[AD1938_SPI_BUFLEN];
-       int ret;
-
-       struct spi_transfer t = {
-               .tx_buf = w_buf,
-               .rx_buf = r_buf,
-               .len = AD1938_SPI_BUFLEN,
-       };
-       struct spi_message m;
-
-       w_buf[0] = (AD1938_SPI_ADDR << 1) | AD1938_SPI_READ;
-       w_buf[1] = reg;
-       w_buf[2] = 0;
-
-       spi_message_init(&m);
-       spi_message_add_tail(&t, &m);
-       ret = spi_sync(codec->control_data, &m);
-       if (ret == 0)
-               return  r_buf[2];
-       else
-               return -EIO;
-}
-
-static int ad1938_fill_cache(struct snd_soc_codec *codec)
-{
-       int i;
-       u8 *reg_cache = codec->reg_cache;
-       struct spi_device *spi = codec->control_data;
-
-       for (i = 0; i < codec->reg_cache_size; i++) {
-               int ret = ad1938_read_reg(codec, i);
-               if (ret == -EIO) {
-                       dev_err(&spi->dev, "AD1938 SPI read failure\n");
-                       return ret;
-               }
-               reg_cache[i] = ret;
-       }
+       snd_soc_write(codec, AD1938_ADC_CTRL1, reg);
 
        return 0;
 }
@@ -512,32 +389,37 @@ static int ad1938_register(struct ad1938_priv *ad1938)
        codec->owner = THIS_MODULE;
        codec->dai = &ad1938_dai;
        codec->num_dai = 1;
-       codec->write = ad1938_write_reg;
-       codec->read = ad1938_read_reg_cache;
-       codec->set_bias_level = ad1938_set_bias_level;
        INIT_LIST_HEAD(&codec->dapm_widgets);
        INIT_LIST_HEAD(&codec->dapm_paths);
 
        ad1938_dai.dev = codec->dev;
        ad1938_codec = codec;
 
+       memcpy(codec->reg_cache, ad1938_reg, AD1938_NUM_REGS);
+
+       ret = snd_soc_codec_set_cache_io(codec, 16, 8, SND_SOC_SPI);
+       if (ret < 0) {
+               dev_err(codec->dev, "failed to set cache I/O: %d\n",
+                               ret);
+               kfree(ad1938);
+               return ret;
+       }
+
        /* default setting for ad1938 */
 
        /* unmute dac channels */
-       codec->write(codec, AD1938_DAC_CHNL_MUTE, 0x0);
+       snd_soc_write(codec, AD1938_DAC_CHNL_MUTE, 0x0);
        /* de-emphasis: 48kHz, powedown dac */
-       codec->write(codec, AD1938_DAC_CTRL2, 0x1A);
+       snd_soc_write(codec, AD1938_DAC_CTRL2, 0x1A);
        /* powerdown dac, dac in tdm mode */
-       codec->write(codec, AD1938_DAC_CTRL0, 0x41);
+       snd_soc_write(codec, AD1938_DAC_CTRL0, 0x41);
        /* high-pass filter enable */
-       codec->write(codec, AD1938_ADC_CTRL0, 0x3);
+       snd_soc_write(codec, AD1938_ADC_CTRL0, 0x3);
        /* sata delay=1, adc aux mode */
-       codec->write(codec, AD1938_ADC_CTRL1, 0x43);
+       snd_soc_write(codec, AD1938_ADC_CTRL1, 0x43);
        /* pll input: mclki/xi */
-       codec->write(codec, AD1938_PLL_CLK_CTRL0, 0x9D);
-       codec->write(codec, AD1938_PLL_CLK_CTRL1, 0x04);
-
-       ad1938_fill_cache(codec);
+       snd_soc_write(codec, AD1938_PLL_CLK_CTRL0, 0x9D);
+       snd_soc_write(codec, AD1938_PLL_CLK_CTRL1, 0x04);
 
        ret = snd_soc_register_codec(codec);
        if (ret != 0) {
@@ -559,7 +441,6 @@ static int ad1938_register(struct ad1938_priv *ad1938)
 
 static void ad1938_unregister(struct ad1938_priv *ad1938)
 {
-       ad1938_set_bias_level(&ad1938->codec, SND_SOC_BIAS_OFF);
        snd_soc_unregister_dai(&ad1938_dai);
        snd_soc_unregister_codec(&ad1938->codec);
        kfree(ad1938);
@@ -593,7 +474,6 @@ static int ad1938_probe(struct platform_device *pdev)
                                  ARRAY_SIZE(ad1938_dapm_widgets));
        snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
 
-       ad1938_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
 pcm_err:
        return ret;
@@ -610,37 +490,9 @@ static int ad1938_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int ad1938_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;
-
-       ad1938_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       return 0;
-}
-
-static int ad1938_resume(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (codec->suspend_bias_level == SND_SOC_BIAS_ON)
-               ad1938_set_bias_level(codec, SND_SOC_BIAS_ON);
-
-       return 0;
-}
-#else
-#define ad1938_suspend NULL
-#define ad1938_resume NULL
-#endif
-
 struct snd_soc_codec_device soc_codec_dev_ad1938 = {
        .probe =        ad1938_probe,
        .remove =       ad1938_remove,
-       .suspend =      ad1938_suspend,
-       .resume =       ad1938_resume,
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_ad1938);
 
index 3a14c6fc4f5ee45ece90bbf092bf4ba9e30cfc09..b9ef7e45891d3c238597a750f762ea4bcbf3ef96 100644 (file)
@@ -185,9 +185,7 @@ struct snd_soc_dai ak4104_dai = {
                .stream_name = "Playback",
                .channels_min = 2,
                .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_44100 |
-                        SNDRV_PCM_RATE_48000 |
-                        SNDRV_PCM_RATE_32000,
+               .rates = SNDRV_PCM_RATE_8000_192000,
                .formats = SNDRV_PCM_FMTBIT_S16_LE  |
                           SNDRV_PCM_FMTBIT_S24_3LE |
                           SNDRV_PCM_FMTBIT_S24_LE
index ffe122d1cd76af149d510fe3c80fff4380922bbd..dfbeb2db61b3e25011c24276cab47a58425aa788 100644 (file)
@@ -28,6 +28,7 @@
 #include <sound/initval.h>
 #include <linux/i2c.h>
 #include <linux/delay.h>
+#include <linux/regulator/consumer.h>
 
 #include "cs4270.h"
 
 #define CS4270_MUTE_DAC_A      0x01
 #define CS4270_MUTE_DAC_B      0x02
 
+static const char *supply_names[] = {
+       "va", "vd", "vlc"
+};
+
 /* Private data for the CS4270 */
 struct cs4270_private {
        struct snd_soc_codec codec;
@@ -114,6 +119,9 @@ struct cs4270_private {
        unsigned int mode; /* The mode (I2S or left-justified) */
        unsigned int slave_mode;
        unsigned int manual_mute;
+
+       /* power domain regulators */
+       struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
 };
 
 /**
@@ -192,6 +200,11 @@ static struct cs4270_mode_ratios cs4270_mode_ratios[] = {
  * This function must be called by the machine driver's 'startup' function,
  * otherwise the list of supported sample rates will not be available in
  * time for ALSA.
+ *
+ * For setups with variable MCLKs, pass 0 as 'freq' argument. This will cause
+ * theoretically possible sample rates to be enabled. Call it again with a
+ * proper value set one the external clock is set (most probably you would do
+ * that from a machine's driver 'hw_param' hook.
  */
 static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai,
                                 int clk_id, unsigned int freq, int dir)
@@ -205,20 +218,27 @@ static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 
        cs4270->mclk = freq;
 
-       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 (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;
+               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;
@@ -579,7 +599,8 @@ static int cs4270_probe(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
        struct snd_soc_codec *codec = cs4270_codec;
-       int ret;
+       struct cs4270_private *cs4270 = codec->private_data;
+       int i, ret;
 
        /* Connect the codec to the socdev.  snd_soc_new_pcms() needs this. */
        socdev->card->codec = codec;
@@ -599,8 +620,26 @@ static int cs4270_probe(struct platform_device *pdev)
                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);
 
@@ -616,8 +655,12 @@ error_free_pcms:
 static int cs4270_remove(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = cs4270_codec;
+       struct cs4270_private *cs4270 = codec->private_data;
 
        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;
 };
@@ -799,17 +842,33 @@ MODULE_DEVICE_TABLE(i2c, cs4270_id);
 static int cs4270_soc_suspend(struct platform_device *pdev, pm_message_t mesg)
 {
        struct snd_soc_codec *codec = cs4270_codec;
-       int reg = snd_soc_read(codec, CS4270_PWRCTL) | CS4270_PWRCTL_PDN_ALL;
+       struct cs4270_private *cs4270 = codec->private_data;
+       int reg, ret;
 
-       return snd_soc_write(codec, CS4270_PWRCTL, reg);
+       reg = snd_soc_read(codec, CS4270_PWRCTL) | CS4270_PWRCTL_PDN_ALL;
+       if (reg < 0)
+               return reg;
+
+       ret = snd_soc_write(codec, CS4270_PWRCTL, reg);
+       if (ret < 0)
+               return ret;
+
+       regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies),
+                              cs4270->supplies);
+
+       return 0;
 }
 
 static int cs4270_soc_resume(struct platform_device *pdev)
 {
        struct snd_soc_codec *codec = cs4270_codec;
+       struct cs4270_private *cs4270 = codec->private_data;
        struct i2c_client *i2c_client = codec->control_data;
        int reg;
 
+       regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
+                             cs4270->supplies);
+
        /* In case the device was put to hard reset during sleep, we need to
         * wait 500ns here before any I2C communication. */
        ndelay(500);
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
new file mode 100644 (file)
index 0000000..cf2975a
--- /dev/null
@@ -0,0 +1,589 @@
+/*
+ * DA7210 ALSA Soc codec driver
+ *
+ * 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>
+ *
+ * Tested on SuperH Ecovec24 board with S16/S24 LE in 48KHz using I2S
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the 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/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/tlv.h>
+#include <sound/initval.h>
+#include <asm/div64.h>
+
+#include "da7210.h"
+
+/* DA7210 register space */
+#define DA7210_STATUS                  0x02
+#define DA7210_STARTUP1                        0x03
+#define DA7210_MIC_L                   0x07
+#define DA7210_MIC_R                   0x08
+#define DA7210_INMIX_L                 0x0D
+#define DA7210_INMIX_R                 0x0E
+#define DA7210_ADC_HPF                 0x0F
+#define DA7210_ADC                     0x10
+#define DA7210_DAC_HPF                 0x14
+#define DA7210_DAC_L                   0x15
+#define DA7210_DAC_R                   0x16
+#define DA7210_DAC_SEL                 0x17
+#define DA7210_OUTMIX_L                        0x1C
+#define DA7210_OUTMIX_R                        0x1D
+#define DA7210_HP_L_VOL                        0x21
+#define DA7210_HP_R_VOL                        0x22
+#define DA7210_HP_CFG                  0x23
+#define DA7210_DAI_SRC_SEL             0x25
+#define DA7210_DAI_CFG1                        0x26
+#define DA7210_DAI_CFG3                        0x28
+#define DA7210_PLL_DIV3                        0x2B
+#define DA7210_PLL                     0x2C
+
+/* STARTUP1 bit fields */
+#define DA7210_SC_MST_EN               (1 << 0)
+
+/* MIC_L bit fields */
+#define DA7210_MICBIAS_EN              (1 << 6)
+#define DA7210_MIC_L_EN                        (1 << 7)
+
+/* MIC_R bit fields */
+#define DA7210_MIC_R_EN                        (1 << 7)
+
+/* INMIX_L bit fields */
+#define DA7210_IN_L_EN                 (1 << 7)
+
+/* INMIX_R bit fields */
+#define DA7210_IN_R_EN                 (1 << 7)
+
+/* ADC_HPF bit fields */
+#define DA7210_ADC_VOICE_EN            (1 << 7)
+
+/* ADC bit fields */
+#define DA7210_ADC_L_EN                        (1 << 3)
+#define DA7210_ADC_R_EN                        (1 << 7)
+
+/* DAC_HPF fields */
+#define DA7210_DAC_VOICE_EN            (1 << 7)
+
+/* DAC_SEL bit fields */
+#define DA7210_DAC_L_SRC_DAI_L         (4 << 0)
+#define DA7210_DAC_L_EN                        (1 << 3)
+#define DA7210_DAC_R_SRC_DAI_R         (5 << 4)
+#define DA7210_DAC_R_EN                        (1 << 7)
+
+/* OUTMIX_L bit fields */
+#define DA7210_OUT_L_EN                        (1 << 7)
+
+/* OUTMIX_R bit fields */
+#define DA7210_OUT_R_EN                        (1 << 7)
+
+/* HP_CFG bit fields */
+#define DA7210_HP_2CAP_MODE            (1 << 1)
+#define DA7210_HP_SENSE_EN             (1 << 2)
+#define DA7210_HP_L_EN                 (1 << 3)
+#define DA7210_HP_MODE                 (1 << 6)
+#define DA7210_HP_R_EN                 (1 << 7)
+
+/* DAI_SRC_SEL bit fields */
+#define DA7210_DAI_OUT_L_SRC           (6 << 0)
+#define DA7210_DAI_OUT_R_SRC           (7 << 4)
+
+/* DAI_CFG1 bit fields */
+#define DA7210_DAI_WORD_S16_LE         (0 << 0)
+#define DA7210_DAI_WORD_S24_LE         (2 << 0)
+#define DA7210_DAI_FLEN_64BIT          (1 << 2)
+#define DA7210_DAI_MODE_MASTER         (1 << 7)
+
+/* DAI_CFG3 bit fields */
+#define DA7210_DAI_FORMAT_I2SMODE      (0 << 0)
+#define DA7210_DAI_OE                  (1 << 3)
+#define DA7210_DAI_EN                  (1 << 7)
+
+/*PLL_DIV3 bit fields */
+#define DA7210_MCLK_RANGE_10_20_MHZ    (1 << 4)
+#define DA7210_PLL_BYP                 (1 << 6)
+
+/* PLL bit fields */
+#define DA7210_PLL_FS_48000            (11 << 0)
+
+#define DA7210_VERSION "0.0.1"
+
+/* Codec private data */
+struct da7210_priv {
+       struct snd_soc_codec codec;
+};
+
+static struct snd_soc_codec *da7210_codec;
+
+/*
+ * Register cache
+ */
+static const u8 da7210_reg[] = {
+       0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R0  - R7  */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, /* R8  - RF  */
+       0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x10, 0x54, /* R10 - R17 */
+       0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R18 - R1F */
+       0x00, 0x00, 0x00, 0x02, 0x00, 0x76, 0x00, 0x00, /* R20 - R27 */
+       0x04, 0x00, 0x00, 0x30, 0x2A, 0x00, 0x40, 0x00, /* R28 - R2F */
+       0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, /* R30 - R37 */
+       0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, /* R38 - R3F */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R40 - R4F */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R48 - R4F */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R50 - R57 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R58 - R5F */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R60 - R67 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R68 - R6F */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R70 - R77 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x54, 0x00, /* R78 - R7F */
+       0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, /* R80 - R87 */
+       0x00,                                           /* R88       */
+};
+
+/*
+ * Read da7210 register cache
+ */
+static inline u32 da7210_read_reg_cache(struct snd_soc_codec *codec, u32 reg)
+{
+       u8 *cache = codec->reg_cache;
+       BUG_ON(reg > ARRAY_SIZE(da7210_reg));
+       return cache[reg];
+}
+
+/*
+ * Write to the da7210 register space
+ */
+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);
+
+       data[0] = reg & 0xff;
+       data[1] = value & 0xff;
+
+       if (reg >= codec->reg_cache_size)
+               return -EIO;
+
+       if (2 != codec->hw_write(codec->control_data, data, 2))
+               return -EIO;
+
+       cache[reg] = value;
+       return 0;
+}
+
+/*
+ * Read from the da7210 register space.
+ */
+static inline u32 da7210_read(struct snd_soc_codec *codec, u32 reg)
+{
+       if (DA7210_STATUS == reg)
+               return i2c_smbus_read_byte_data(codec->control_data, reg);
+
+       return da7210_read_reg_cache(codec, reg);
+}
+
+static int da7210_startup(struct snd_pcm_substream *substream,
+                         struct snd_soc_dai *dai)
+{
+       int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       struct snd_soc_codec *codec = dai->codec;
+
+       if (is_play) {
+               /* PlayBack Volume 40 */
+               snd_soc_update_bits(codec, DA7210_HP_L_VOL, 0x3F, 40);
+               snd_soc_update_bits(codec, DA7210_HP_R_VOL, 0x3F, 40);
+
+               /* Enable Out */
+               snd_soc_update_bits(codec, DA7210_OUTMIX_L, 0x1F, 0x10);
+               snd_soc_update_bits(codec, DA7210_OUTMIX_R, 0x1F, 0x10);
+
+       } else {
+               /* Volume 7 */
+               snd_soc_update_bits(codec, DA7210_MIC_L, 0x7, 0x7);
+               snd_soc_update_bits(codec, DA7210_MIC_R, 0x7, 0x7);
+
+               /* Enable Mic */
+               snd_soc_update_bits(codec, DA7210_INMIX_L, 0x1F, 0x1);
+               snd_soc_update_bits(codec, DA7210_INMIX_R, 0x1F, 0x1);
+       }
+
+       return 0;
+}
+
+/*
+ * Set PCM DAI word length.
+ */
+static int da7210_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;
+       u32 dai_cfg1;
+       u32 reg, mask;
+
+       /* set DAI source to Left and Right ADC */
+       da7210_write(codec, DA7210_DAI_SRC_SEL,
+                    DA7210_DAI_OUT_R_SRC | DA7210_DAI_OUT_L_SRC);
+
+       /* Enable DAI */
+       da7210_write(codec, DA7210_DAI_CFG3, DA7210_DAI_OE | DA7210_DAI_EN);
+
+       dai_cfg1 = 0xFC & da7210_read(codec, DA7210_DAI_CFG1);
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               dai_cfg1 |= DA7210_DAI_WORD_S16_LE;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               dai_cfg1 |= DA7210_DAI_WORD_S24_LE;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       da7210_write(codec, DA7210_DAI_CFG1, dai_cfg1);
+
+       /* FIXME
+        *
+        * It support 48K only now
+        */
+       switch (params_rate(params)) {
+       case 48000:
+               if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
+                       reg  = DA7210_DAC_HPF;
+                       mask = DA7210_DAC_VOICE_EN;
+               } else {
+                       reg  = DA7210_ADC_HPF;
+                       mask = DA7210_ADC_VOICE_EN;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, reg, mask, 0);
+
+       return 0;
+}
+
+/*
+ * Set DAI mode and Format
+ */
+static int da7210_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u32 dai_cfg1;
+       u32 dai_cfg3;
+
+       dai_cfg1 = 0x7f & da7210_read(codec, DA7210_DAI_CFG1);
+       dai_cfg3 = 0xfc & da7210_read(codec, DA7210_DAI_CFG3);
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               dai_cfg1 |= DA7210_DAI_MODE_MASTER;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* FIXME
+        *
+        * It support I2S only now
+        */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               dai_cfg3 |= DA7210_DAI_FORMAT_I2SMODE;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* FIXME
+        *
+        * It support 64bit data transmission only now
+        */
+       dai_cfg1 |= DA7210_DAI_FLEN_64BIT;
+
+       da7210_write(codec, DA7210_DAI_CFG1, dai_cfg1);
+       da7210_write(codec, DA7210_DAI_CFG3, dai_cfg3);
+
+       return 0;
+}
+
+#define DA7210_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
+
+/* DAI operations */
+static struct snd_soc_dai_ops da7210_dai_ops = {
+       .startup        = da7210_startup,
+       .hw_params      = da7210_hw_params,
+       .set_fmt        = da7210_set_dai_fmt,
+};
+
+struct snd_soc_dai da7210_dai = {
+       .name = "DA7210 IIS",
+       .id = 0,
+       /* playback capabilities */
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = DA7210_FORMATS,
+       },
+       /* capture capabilities */
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = DA7210_FORMATS,
+       },
+       .ops = &da7210_dai_ops,
+};
+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)
+{
+       struct snd_soc_codec *codec = &da7210->codec;
+       int ret = 0;
+
+       if (da7210_codec) {
+               dev_err(codec->dev, "Another da7210 is registered\n");
+               return -EINVAL;
+       }
+
+       mutex_init(&codec->mutex);
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+
+       codec->private_data     = 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->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 init_err;
+       }
+
+       /* FIXME
+        *
+        * This driver use fixed value here
+        */
+
+       /*
+        * ADC settings
+        */
+
+       /* Enable Left & Right MIC PGA and Mic Bias */
+       da7210_write(codec, DA7210_MIC_L, DA7210_MIC_L_EN | DA7210_MICBIAS_EN);
+       da7210_write(codec, DA7210_MIC_R, DA7210_MIC_R_EN);
+
+       /* Enable Left and Right input PGA */
+       da7210_write(codec, DA7210_INMIX_L, DA7210_IN_L_EN);
+       da7210_write(codec, DA7210_INMIX_R, DA7210_IN_R_EN);
+
+       /* Enable Left and Right ADC */
+       da7210_write(codec, DA7210_ADC, DA7210_ADC_L_EN | DA7210_ADC_R_EN);
+
+       /*
+        * DAC settings
+        */
+
+       /* Enable Left and Right DAC */
+       da7210_write(codec, DA7210_DAC_SEL,
+                    DA7210_DAC_L_SRC_DAI_L | DA7210_DAC_L_EN |
+                    DA7210_DAC_R_SRC_DAI_R | DA7210_DAC_R_EN);
+
+       /* Enable Left and Right out PGA */
+       da7210_write(codec, DA7210_OUTMIX_L, DA7210_OUT_L_EN);
+       da7210_write(codec, DA7210_OUTMIX_R, DA7210_OUT_R_EN);
+
+       /* Enable Left and Right HeadPhone PGA */
+       da7210_write(codec, DA7210_HP_CFG,
+                    DA7210_HP_2CAP_MODE | DA7210_HP_SENSE_EN |
+                    DA7210_HP_L_EN | DA7210_HP_MODE | DA7210_HP_R_EN);
+
+       /* Diable PLL and bypass it */
+       da7210_write(codec, DA7210_PLL, DA7210_PLL_FS_48000);
+
+       /* Bypass PLL and set MCLK freq rang to 10-20MHz */
+       da7210_write(codec, DA7210_PLL_DIV3,
+                    DA7210_MCLK_RANGE_10_20_MHZ | DA7210_PLL_BYP);
+
+       /* Activate all enabled subsystem */
+       da7210_write(codec, DA7210_STARTUP1, DA7210_SC_MST_EN);
+
+       return ret;
+
+init_err:
+       kfree(codec->reg_cache);
+       codec->reg_cache = NULL;
+
+       return ret;
+
+}
+
+#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;
+
+       ret = da7210_init(da7210);
+       if (ret < 0)
+               pr_err("Failed to initialise da7210 audio codec\n");
+
+       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;
+
+       return 0;
+}
+
+static const struct i2c_device_id da7210_i2c_id[] = {
+       { "da7210", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, da7210_i2c_id);
+
+/* I2C codec control layer */
+static struct i2c_driver da7210_i2c_driver = {
+       .driver = {
+               .name = "DA7210 I2C Codec",
+               .owner = THIS_MODULE,
+       },
+       .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;
+
+       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;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&da7210_i2c_driver);
+#endif
+       return ret;
+}
+module_init(da7210_modinit);
+
+static void __exit da7210_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&da7210_i2c_driver);
+#endif
+}
+module_exit(da7210_exit);
+
+MODULE_DESCRIPTION("ASoC DA7210 driver");
+MODULE_AUTHOR("David Chen, Kuninori Morimoto");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/da7210.h b/sound/soc/codecs/da7210.h
new file mode 100644 (file)
index 0000000..390d621
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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 2b4dc2b0b01724aa91507e330860d9d7bc7e0eda..e4b946a19ea3e958b46969be2561e03764c1096d 100644 (file)
@@ -765,9 +765,10 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_codec *codec = socdev->card->codec;
        struct aic3x_priv *aic3x = codec->private_data;
        int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0;
-       u8 data, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
-       u16 pll_d = 1;
+       u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
+       u16 d, pll_d = 1;
        u8 reg;
+       int clk;
 
        /* select data word length */
        data =
@@ -833,48 +834,70 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
        if (bypass_pll)
                return 0;
 
-       /* Use PLL
-        * find an apropriate setup for j, d, r and p by iterating over
-        * p and r - j and d are calculated for each fraction.
-        * Up to 128 values are probed, the closest one wins the game.
+       /* Use PLL, compute apropriate setup for j, d, r and p, the closest
+        * one wins the game. Try with d==0 first, next with d!=0.
+        * Constraints for j are according to the datasheet.
         * The sysclk is divided by 1000 to prevent integer overflows.
         */
+
        codec_clk = (2048 * fsref) / (aic3x->sysclk / 1000);
 
        for (r = 1; r <= 16; r++)
                for (p = 1; p <= 8; p++) {
-                       int clk, tmp = (codec_clk * pll_r * 10) / pll_p;
-                       u8 j = tmp / 10000;
-                       u16 d = tmp % 10000;
+                       for (j = 4; j <= 55; j++) {
+                               /* This is actually 1000*((j+(d/10000))*r)/p
+                                * The term had to be converted to get
+                                * rid of the division by 10000; d = 0 here
+                                */
+                               int tmp_clk = (1000 * j * r) / p;
+
+                               /* Check whether this values get closer than
+                                * the best ones we had before
+                                */
+                               if (abs(codec_clk - tmp_clk) <
+                                       abs(codec_clk - last_clk)) {
+                                       pll_j = j; pll_d = 0;
+                                       pll_r = r; pll_p = p;
+                                       last_clk = tmp_clk;
+                               }
+
+                               /* Early exit for exact matches */
+                               if (tmp_clk == codec_clk)
+                                       goto found;
+                       }
+               }
 
-                       if (j > 63)
-                               continue;
+       /* try with d != 0 */
+       for (p = 1; p <= 8; p++) {
+               j = codec_clk * p / 1000;
 
-                       if (d != 0 && aic3x->sysclk < 10000000)
-                               continue;
+               if (j < 4 || j > 11)
+                       continue;
 
-                       /* This is actually 1000 * ((j + (d/10000)) * r) / p
-                        * The term had to be converted to get rid of the
-                        * division by 10000 */
-                       clk = ((10000 * j * r) + (d * r)) / (10 * p);
+               /* do not use codec_clk here since we'd loose precision */
+               d = ((2048 * p * fsref) - j * aic3x->sysclk)
+                       * 100 / (aic3x->sysclk/100);
 
-                       /* check whether this values get closer than the best
-                        * ones we had before */
-                       if (abs(codec_clk - clk) < abs(codec_clk - last_clk)) {
-                               pll_j = j; pll_d = d; pll_r = r; pll_p = p;
-                               last_clk = clk;
-                       }
+               clk = (10000 * j + d) / (10 * p);
 
-                       /* Early exit for exact matches */
-                       if (clk == codec_clk)
-                               break;
+               /* check whether this values get closer than the best
+                * ones we had before */
+               if (abs(codec_clk - clk) < abs(codec_clk - last_clk)) {
+                       pll_j = j; pll_d = d; pll_r = 1; pll_p = p;
+                       last_clk = clk;
                }
 
+               /* Early exit for exact matches */
+               if (clk == codec_clk)
+                       goto found;
+       }
+
        if (last_clk == 0) {
                printk(KERN_ERR "%s(): unable to setup PLL\n", __func__);
                return -EINVAL;
        }
 
+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);
index 9c8903dbe647c9c658f6bb114c50a5e8df0242da..f9f367d29a9095e8bc5a44be2da0da9b45f4ba7e 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -58,11 +59,26 @@ enum dac33_state {
        DAC33_FLUSH,
 };
 
+enum dac33_fifo_modes {
+       DAC33_FIFO_BYPASS = 0,
+       DAC33_FIFO_MODE1,
+       DAC33_FIFO_MODE7,
+       DAC33_FIFO_LAST_MODE,
+};
+
+#define DAC33_NUM_SUPPLIES 3
+static const char *dac33_supply_names[DAC33_NUM_SUPPLIES] = {
+       "AVDD",
+       "DVDD",
+       "IOVDD",
+};
+
 struct tlv320dac33_priv {
        struct mutex mutex;
        struct workqueue_struct *dac33_wq;
        struct work_struct work;
        struct snd_soc_codec codec;
+       struct regulator_bulk_data supplies[DAC33_NUM_SUPPLIES];
        int power_gpio;
        int chip_power;
        int irq;
@@ -73,8 +89,9 @@ struct tlv320dac33_priv {
                                         * this */
        unsigned int nsample_max;       /* nsample should not be higher than
                                         * this */
-       unsigned int nsample_switch;    /* Use FIFO or bypass FIFO switch */
+       enum dac33_fifo_modes fifo_mode;/* FIFO mode selection */
        unsigned int nsample;           /* burst read amount from host */
+       u8 burst_bclkdiv;               /* BCLK divider value in burst mode */
 
        enum dac33_state state;
 };
@@ -297,28 +314,49 @@ static inline void dac33_soft_power(struct snd_soc_codec *codec, int power)
        dac33_write(codec, DAC33_PWR_CTRL, reg);
 }
 
-static void dac33_hard_power(struct snd_soc_codec *codec, int power)
+static int dac33_hard_power(struct snd_soc_codec *codec, int power)
 {
        struct tlv320dac33_priv *dac33 = codec->private_data;
+       int ret;
 
        mutex_lock(&dac33->mutex);
        if (power) {
-               if (dac33->power_gpio >= 0) {
-                       gpio_set_value(dac33->power_gpio, 1);
-                       dac33->chip_power = 1;
-                       /* Restore registers */
-                       dac33_restore_regs(codec);
+               ret = regulator_bulk_enable(ARRAY_SIZE(dac33->supplies),
+                                         dac33->supplies);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to enable supplies: %d\n", ret);
+                               goto exit;
                }
+
+               if (dac33->power_gpio >= 0)
+                       gpio_set_value(dac33->power_gpio, 1);
+
+               dac33->chip_power = 1;
+
+               /* Restore registers */
+               dac33_restore_regs(codec);
+
                dac33_soft_power(codec, 1);
        } else {
                dac33_soft_power(codec, 0);
-               if (dac33->power_gpio >= 0) {
+               if (dac33->power_gpio >= 0)
                        gpio_set_value(dac33->power_gpio, 0);
-                       dac33->chip_power = 0;
+
+               ret = regulator_bulk_disable(ARRAY_SIZE(dac33->supplies),
+                                            dac33->supplies);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to disable supplies: %d\n", ret);
+                       goto exit;
                }
+
+               dac33->chip_power = 0;
        }
-       mutex_unlock(&dac33->mutex);
 
+exit:
+       mutex_unlock(&dac33->mutex);
+       return ret;
 }
 
 static int dac33_get_nsample(struct snd_kcontrol *kcontrol,
@@ -351,39 +389,48 @@ static int dac33_set_nsample(struct snd_kcontrol *kcontrol,
        return ret;
 }
 
-static int dac33_get_nsample_switch(struct snd_kcontrol *kcontrol,
+static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol,
                         struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
        struct tlv320dac33_priv *dac33 = codec->private_data;
 
-       ucontrol->value.integer.value[0] = dac33->nsample_switch;
+       ucontrol->value.integer.value[0] = dac33->fifo_mode;
 
        return 0;
 }
 
-static int dac33_set_nsample_switch(struct snd_kcontrol *kcontrol,
+static int dac33_set_fifo_mode(struct snd_kcontrol *kcontrol,
                         struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
        struct tlv320dac33_priv *dac33 = codec->private_data;
        int ret = 0;
 
-       if (dac33->nsample_switch == ucontrol->value.integer.value[0])
+       if (dac33->fifo_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] > 1)
+           ucontrol->value.integer.value[0] >= DAC33_FIFO_LAST_MODE)
                ret = -EINVAL;
        else
-               dac33->nsample_switch = ucontrol->value.integer.value[0];
+               dac33->fifo_mode = ucontrol->value.integer.value[0];
 
        return ret;
 }
 
+/* Codec operation modes */
+static const char *dac33_fifo_mode_texts[] = {
+       "Bypass", "Mode 1", "Mode 7"
+};
+
+static const struct soc_enum dac33_fifo_mode_enum =
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dac33_fifo_mode_texts),
+                           dac33_fifo_mode_texts);
+
 /*
  * DACL/R digital volume control:
  * from 0 dB to -63.5 in 0.5 dB steps
@@ -406,8 +453,8 @@ static const struct snd_kcontrol_new dac33_snd_controls[] = {
 static const struct snd_kcontrol_new dac33_nsample_snd_controls[] = {
        SOC_SINGLE_EXT("nSample", 0, 0, 5900, 0,
                 dac33_get_nsample, dac33_set_nsample),
-       SOC_SINGLE_EXT("nSample Switch", 0, 0, 1, 0,
-                dac33_get_nsample_switch, dac33_set_nsample_switch),
+       SOC_ENUM_EXT("FIFO Mode", dac33_fifo_mode_enum,
+                dac33_get_fifo_mode, dac33_set_fifo_mode),
 };
 
 /* Analog bypass */
@@ -469,6 +516,8 @@ static int dac33_add_widgets(struct snd_soc_codec *codec)
 static int dac33_set_bias_level(struct snd_soc_codec *codec,
                                enum snd_soc_bias_level level)
 {
+       int ret;
+
        switch (level) {
        case SND_SOC_BIAS_ON:
                dac33_soft_power(codec, 1);
@@ -476,12 +525,19 @@ static int dac33_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_PREPARE:
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->bias_level == SND_SOC_BIAS_OFF)
-                       dac33_hard_power(codec, 1);
+               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+                       ret = dac33_hard_power(codec, 1);
+                       if (ret != 0)
+                               return ret;
+               }
+
                dac33_soft_power(codec, 0);
                break;
        case SND_SOC_BIAS_OFF:
-               dac33_hard_power(codec, 0);
+               ret = dac33_hard_power(codec, 0);
+               if (ret != 0)
+                       return ret;
+
                break;
        }
        codec->bias_level = level;
@@ -489,6 +545,51 @@ static int dac33_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
+static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
+{
+       struct snd_soc_codec *codec;
+
+       codec = &dac33->codec;
+
+       switch (dac33->fifo_mode) {
+       case DAC33_FIFO_MODE1:
+               dac33_write16(codec, DAC33_NSAMPLE_MSB,
+                               DAC33_THRREG(dac33->nsample));
+               dac33_write16(codec, DAC33_PREFILL_MSB,
+                               DAC33_THRREG(dac33->alarm_threshold));
+               break;
+       case DAC33_FIFO_MODE7:
+               dac33_write16(codec, DAC33_PREFILL_MSB,
+                               DAC33_THRREG(10));
+               break;
+       default:
+               dev_warn(codec->dev, "Unhandled FIFO mode: %d\n",
+                                                       dac33->fifo_mode);
+               break;
+       }
+}
+
+static inline void dac33_playback_handler(struct tlv320dac33_priv *dac33)
+{
+       struct snd_soc_codec *codec;
+
+       codec = &dac33->codec;
+
+       switch (dac33->fifo_mode) {
+       case DAC33_FIFO_MODE1:
+               dac33_write16(codec, DAC33_NSAMPLE_MSB,
+                               DAC33_THRREG(dac33->nsample));
+               break;
+       case DAC33_FIFO_MODE7:
+               /* At the moment we are not using interrupts in mode7 */
+               break;
+       default:
+               dev_warn(codec->dev, "Unhandled FIFO mode: %d\n",
+                                                       dac33->fifo_mode);
+               break;
+       }
+}
+
 static void dac33_work(struct work_struct *work)
 {
        struct snd_soc_codec *codec;
@@ -502,14 +603,10 @@ static void dac33_work(struct work_struct *work)
        switch (dac33->state) {
        case DAC33_PREFILL:
                dac33->state = DAC33_PLAYBACK;
-               dac33_write16(codec, DAC33_NSAMPLE_MSB,
-                               DAC33_THRREG(dac33->nsample));
-               dac33_write16(codec, DAC33_PREFILL_MSB,
-                               DAC33_THRREG(dac33->alarm_threshold));
+               dac33_prefill_handler(dac33);
                break;
        case DAC33_PLAYBACK:
-               dac33_write16(codec, DAC33_NSAMPLE_MSB,
-                               DAC33_THRREG(dac33->nsample));
+               dac33_playback_handler(dac33);
                break;
        case DAC33_IDLE:
                break;
@@ -547,7 +644,7 @@ static void dac33_shutdown(struct snd_pcm_substream *substream,
        unsigned int pwr_ctrl;
 
        /* Stop pending workqueue */
-       if (dac33->nsample_switch)
+       if (dac33->fifo_mode)
                cancel_work_sync(&dac33->work);
 
        mutex_lock(&dac33->mutex);
@@ -603,7 +700,7 @@ static int dac33_hw_params(struct snd_pcm_substream *substream,
 }
 
 #define CALC_OSCSET(rate, refclk) ( \
-       ((((rate * 10000) / refclk) * 4096) + 5000) / 10000)
+       ((((rate * 10000) / refclk) * 4096) + 7000) / 10000)
 #define CALC_RATIOSET(rate, refclk) ( \
        ((((refclk  * 100000) / rate) * 16384) + 50000) / 100000)
 
@@ -619,7 +716,7 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
        struct snd_soc_codec *codec = socdev->card->codec;
        struct tlv320dac33_priv *dac33 = codec->private_data;
        unsigned int oscset, ratioset, pwr_ctrl, reg_tmp;
-       u8 aictrl_a, fifoctrl_a;
+       u8 aictrl_a, aictrl_b, fifoctrl_a;
 
        switch (substream->runtime->rate) {
        case 44100:
@@ -637,7 +734,10 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
 
        aictrl_a = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_A);
        aictrl_a &= ~(DAC33_NCYCL_MASK | DAC33_WLEN_MASK);
+       /* Read FIFO control A, and clear FIFO flush bit */
        fifoctrl_a = dac33_read_reg_cache(codec, DAC33_FIFO_CTRL_A);
+       fifoctrl_a &= ~DAC33_FIFOFLUSH;
+
        fifoctrl_a &= ~DAC33_WIDTH;
        switch (substream->runtime->format) {
        case SNDRV_PCM_FORMAT_S16_LE:
@@ -675,7 +775,8 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
 
        dac33_oscwait(codec);
 
-       if (dac33->nsample_switch) {
+       if (dac33->fifo_mode) {
+               /* Generic for all FIFO modes */
                /* 50-51 : ASRC Control registers */
                dac33_write(codec, DAC33_ASRC_CTRL_A, (1 << 4)); /* div=2 */
                dac33_write(codec, DAC33_ASRC_CTRL_B, 1); /* ??? */
@@ -685,38 +786,101 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
 
                /* Set interrupts to high active */
                dac33_write(codec, DAC33_INTP_CTRL_A, DAC33_INTPM_AHIGH);
-
-               dac33_write(codec, DAC33_FIFO_IRQ_MODE_B,
-                           DAC33_ATM(DAC33_FIFO_IRQ_MODE_LEVEL));
-               dac33_write(codec, DAC33_FIFO_IRQ_MASK, DAC33_MAT);
        } else {
+               /* FIFO bypass mode */
                /* 50-51 : ASRC Control registers */
                dac33_write(codec, DAC33_ASRC_CTRL_A, DAC33_SRCBYP);
                dac33_write(codec, DAC33_ASRC_CTRL_B, 0); /* ??? */
        }
 
-       if (dac33->nsample_switch)
+       /* Interrupt behaviour configuration */
+       switch (dac33->fifo_mode) {
+       case DAC33_FIFO_MODE1:
+               dac33_write(codec, DAC33_FIFO_IRQ_MODE_B,
+                           DAC33_ATM(DAC33_FIFO_IRQ_MODE_LEVEL));
+               dac33_write(codec, DAC33_FIFO_IRQ_MASK, DAC33_MAT);
+               break;
+       case DAC33_FIFO_MODE7:
+               /* Disable all interrupts */
+               dac33_write(codec, DAC33_FIFO_IRQ_MASK, 0);
+               break;
+       default:
+               /* in FIFO bypass mode, the interrupts are not used */
+               break;
+       }
+
+       aictrl_b = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_B);
+
+       switch (dac33->fifo_mode) {
+       case DAC33_FIFO_MODE1:
+               /*
+                * For mode1:
+                * Disable the FIFO bypass (Enable the use of FIFO)
+                * Select nSample mode
+                * BCLK is only running when data is needed by DAC33
+                */
                fifoctrl_a &= ~DAC33_FBYPAS;
-       else
+               fifoctrl_a &= ~DAC33_FAUTO;
+               aictrl_b &= ~DAC33_BCLKON;
+               break;
+       case DAC33_FIFO_MODE7:
+               /*
+                * For mode1:
+                * Disable the FIFO bypass (Enable the use of FIFO)
+                * Select Threshold mode
+                * BCLK is only running when data is needed by DAC33
+                */
+               fifoctrl_a &= ~DAC33_FBYPAS;
+               fifoctrl_a |= DAC33_FAUTO;
+               aictrl_b &= ~DAC33_BCLKON;
+               break;
+       default:
+               /*
+                * For FIFO bypass mode:
+                * Enable the FIFO bypass (Disable the FIFO use)
+                * Set the BCLK as continous
+                */
                fifoctrl_a |= DAC33_FBYPAS;
-       dac33_write(codec, DAC33_FIFO_CTRL_A, fifoctrl_a);
+               aictrl_b |= DAC33_BCLKON;
+               break;
+       }
 
+       dac33_write(codec, DAC33_FIFO_CTRL_A, fifoctrl_a);
        dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_A, aictrl_a);
-       reg_tmp = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_B);
-       if (dac33->nsample_switch)
-               reg_tmp &= ~DAC33_BCLKON;
-       else
-               reg_tmp |= DAC33_BCLKON;
-       dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_B, reg_tmp);
+       dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_B, aictrl_b);
 
-       if (dac33->nsample_switch) {
-               /* 20: BCLK divide ratio */
-               dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 3);
+       /*
+        * BCLK divide ratio
+        * 0: 1.5
+        * 1: 1
+        * 2: 2
+        * ...
+        * 254: 254
+        * 255: 255
+        */
+       if (dac33->fifo_mode)
+               dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C,
+                                                       dac33->burst_bclkdiv);
+       else
+               dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 32);
 
+       switch (dac33->fifo_mode) {
+       case DAC33_FIFO_MODE1:
                dac33_write16(codec, DAC33_ATHR_MSB,
                              DAC33_THRREG(dac33->alarm_threshold));
-       } else {
-               dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 32);
+               break;
+       case DAC33_FIFO_MODE7:
+               /*
+                * Configure the threshold levels, and leave 10 sample space
+                * at the bottom, and also at the top of the FIFO
+                */
+               dac33_write16(codec, DAC33_UTHR_MSB,
+                       DAC33_THRREG(DAC33_BUFFER_SIZE_SAMPLES - 10));
+               dac33_write16(codec, DAC33_LTHR_MSB,
+                       DAC33_THRREG(10));
+               break;
+       default:
+               break;
        }
 
        mutex_unlock(&dac33->mutex);
@@ -789,7 +953,7 @@ static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               if (dac33->nsample_switch) {
+               if (dac33->fifo_mode) {
                        dac33->state = DAC33_PREFILL;
                        queue_work(dac33->dac33_wq, &dac33->work);
                }
@@ -797,7 +961,7 @@ static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               if (dac33->nsample_switch) {
+               if (dac33->fifo_mode) {
                        dac33->state = DAC33_FLUSH;
                        queue_work(dac33->dac33_wq, &dac33->work);
                }
@@ -843,6 +1007,7 @@ static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai,
                             unsigned int fmt)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
+       struct tlv320dac33_priv *dac33 = codec->private_data;
        u8 aictrl_a, aictrl_b;
 
        aictrl_a = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_A);
@@ -855,7 +1020,11 @@ static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai,
                break;
        case SND_SOC_DAIFMT_CBS_CFS:
                /* Codec Slave */
-               aictrl_a &= ~(DAC33_MSBCLK | DAC33_MSWCLK);
+               if (dac33->fifo_mode) {
+                       dev_err(codec->dev, "FIFO mode requires master mode\n");
+                       return -EINVAL;
+               } else
+                       aictrl_a &= ~(DAC33_MSBCLK | DAC33_MSWCLK);
                break;
        default:
                return -EINVAL;
@@ -959,6 +1128,9 @@ static int dac33_soc_probe(struct platform_device *pdev)
        /* power on device */
        dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
+       /* Bias level configuration has enabled regulator an extra time */
+       regulator_bulk_disable(ARRAY_SIZE(dac33->supplies), dac33->supplies);
+
        return 0;
 
 pcm_err:
@@ -1033,13 +1205,13 @@ struct snd_soc_dai dac33_dai = {
 };
 EXPORT_SYMBOL_GPL(dac33_dai);
 
-static int dac33_i2c_probe(struct i2c_client *client,
-                          const struct i2c_device_id *id)
+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 = 0;
+       int ret, i;
 
        if (client->dev.platform_data == NULL) {
                dev_err(&client->dev, "Platform data not set\n");
@@ -1080,10 +1252,11 @@ static int dac33_i2c_probe(struct i2c_client *client,
        i2c_set_clientdata(client, dac33);
 
        dac33->power_gpio = pdata->power_gpio;
+       dac33->burst_bclkdiv = pdata->burst_bclkdiv;
        dac33->irq = client->irq;
        dac33->nsample = NSAMPLE_MAX;
        /* Disable FIFO use by default */
-       dac33->nsample_switch = 0;
+       dac33->fifo_mode = DAC33_FIFO_BYPASS;
 
        tlv320dac33_codec = codec;
 
@@ -1130,6 +1303,24 @@ static int dac33_i2c_probe(struct i2c_client *client,
                }
        }
 
+       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),
+                                dac33->supplies);
+
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+               goto err_get;
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(dac33->supplies),
+                                   dac33->supplies);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+               goto err_enable;
+       }
+
        ret = snd_soc_register_codec(codec);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to register codec: %d\n", ret);
@@ -1149,6 +1340,10 @@ static int dac33_i2c_probe(struct i2c_client *client,
        return ret;
 
 error_codec:
+       regulator_bulk_disable(ARRAY_SIZE(dac33->supplies), dac33->supplies);
+err_enable:
+       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);
@@ -1165,7 +1360,7 @@ error_reg:
        return ret;
 }
 
-static int dac33_i2c_remove(struct i2c_client *client)
+static int __devexit dac33_i2c_remove(struct i2c_client *client)
 {
        struct tlv320dac33_priv *dac33;
 
@@ -1177,6 +1372,8 @@ static int dac33_i2c_remove(struct i2c_client *client)
        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);
index 6b650c1aa3d1feba709009736bc84017f687911a..958d49c969ac3d78696f2276f131d9b13ba71d9f 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/device.h>
 #include <linux/i2c.h>
 #include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
 #include <sound/tpa6130a2-plat.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 
 static struct i2c_client *tpa6130a2_client;
 
+#define TPA6130A2_NUM_SUPPLIES 2
+static const char *tpa6130a2_supply_names[TPA6130A2_NUM_SUPPLIES] = {
+       "CPVSS",
+       "Vdd",
+};
+
+static const char *tpa6140a2_supply_names[TPA6130A2_NUM_SUPPLIES] = {
+       "HPVdd",
+       "AVdd",
+};
+
 /* This struct is used to save the context */
 struct tpa6130a2_data {
        struct mutex mutex;
        unsigned char regs[TPA6130A2_CACHEREGNUM];
+       struct regulator_bulk_data supplies[TPA6130A2_NUM_SUPPLIES];
        int power_gpio;
        unsigned char power_state;
 };
@@ -106,10 +119,11 @@ static void tpa6130a2_initialize(void)
                tpa6130a2_i2c_write(i, data->regs[i]);
 }
 
-static void tpa6130a2_power(int power)
+static int tpa6130a2_power(int power)
 {
        struct  tpa6130a2_data *data;
        u8      val;
+       int     ret;
 
        BUG_ON(tpa6130a2_client == NULL);
        data = i2c_get_clientdata(tpa6130a2_client);
@@ -117,11 +131,20 @@ static void tpa6130a2_power(int power)
        mutex_lock(&data->mutex);
        if (power) {
                /* Power on */
-               if (data->power_gpio >= 0) {
+               if (data->power_gpio >= 0)
                        gpio_set_value(data->power_gpio, 1);
-                       data->power_state = 1;
-                       tpa6130a2_initialize();
+
+               ret = regulator_bulk_enable(ARRAY_SIZE(data->supplies),
+                                           data->supplies);
+               if (ret != 0) {
+                       dev_err(&tpa6130a2_client->dev,
+                               "Failed to enable supplies: %d\n", ret);
+                       goto exit;
                }
+
+               data->power_state = 1;
+               tpa6130a2_initialize();
+
                /* Clear SWS */
                val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
                val &= ~TPA6130A2_SWS;
@@ -131,13 +154,25 @@ static void tpa6130a2_power(int power)
                val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
                val |= TPA6130A2_SWS;
                tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val);
+
                /* Power off */
-               if (data->power_gpio >= 0) {
+               if (data->power_gpio >= 0)
                        gpio_set_value(data->power_gpio, 0);
-                       data->power_state = 0;
+
+               ret = regulator_bulk_disable(ARRAY_SIZE(data->supplies),
+                                            data->supplies);
+               if (ret != 0) {
+                       dev_err(&tpa6130a2_client->dev,
+                               "Failed to disable supplies: %d\n", ret);
+                       goto exit;
                }
+
+               data->power_state = 0;
        }
+
+exit:
        mutex_unlock(&data->mutex);
+       return ret;
 }
 
 static int tpa6130a2_get_reg(struct snd_kcontrol *kcontrol,
@@ -237,12 +272,8 @@ static const struct snd_kcontrol_new tpa6130a2_controls[] = {
  */
 static void tpa6130a2_channel_enable(u8 channel, int enable)
 {
-       struct  tpa6130a2_data *data;
        u8      val;
 
-       BUG_ON(tpa6130a2_client == NULL);
-       data = i2c_get_clientdata(tpa6130a2_client);
-
        if (enable) {
                /* Enable channel */
                /* Enable amplifier */
@@ -299,15 +330,17 @@ static int tpa6130a2_right_event(struct snd_soc_dapm_widget *w,
 static int tpa6130a2_supply_event(struct snd_soc_dapm_widget *w,
                struct snd_kcontrol *kcontrol, int event)
 {
+       int ret = 0;
+
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
-               tpa6130a2_power(1);
+               ret = tpa6130a2_power(1);
                break;
        case SND_SOC_DAPM_POST_PMD:
-               tpa6130a2_power(0);
+               ret = tpa6130a2_power(0);
                break;
        }
-       return 0;
+       return ret;
 }
 
 static const struct snd_soc_dapm_widget tpa6130a2_dapm_widgets[] = {
@@ -346,13 +379,13 @@ int tpa6130a2_add_controls(struct snd_soc_codec *codec)
 }
 EXPORT_SYMBOL_GPL(tpa6130a2_add_controls);
 
-static int tpa6130a2_probe(struct i2c_client *client,
-                          const struct i2c_device_id *id)
+static int __devinit tpa6130a2_probe(struct i2c_client *client,
+                                    const struct i2c_device_id *id)
 {
        struct device *dev;
        struct tpa6130a2_data *data;
        struct tpa6130a2_platform_data *pdata;
-       int ret;
+       int i, ret;
 
        dev = &client->dev;
 
@@ -387,15 +420,38 @@ static int tpa6130a2_probe(struct i2c_client *client,
                if (ret < 0) {
                        dev_err(dev, "Failed to request power GPIO (%d)\n",
                                data->power_gpio);
-                       goto fail;
+                       goto err_gpio;
                }
                gpio_direction_output(data->power_gpio, 0);
-       } else {
-               data->power_state = 1;
-               tpa6130a2_initialize();
        }
 
-       tpa6130a2_power(1);
+       switch (pdata->id) {
+       case TPA6130A2:
+               for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
+                       data->supplies[i].supply = tpa6130a2_supply_names[i];
+               break;
+       case TPA6140A2:
+               for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
+                       data->supplies[i].supply = tpa6140a2_supply_names[i];;
+               break;
+       default:
+               dev_warn(dev, "Unknown TPA model (%d). Assuming 6130A2\n",
+                        pdata->id);
+               for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
+                       data->supplies[i].supply = tpa6130a2_supply_names[i];
+       }
+
+       ret = regulator_bulk_get(dev, ARRAY_SIZE(data->supplies),
+                                data->supplies);
+       if (ret != 0) {
+               dev_err(dev, "Failed to request supplies: %d\n", ret);
+               goto err_regulator;
+       }
+
+       ret = tpa6130a2_power(1);
+       if (ret != 0)
+               goto err_power;
+
 
        /* Read version */
        ret = tpa6130a2_i2c_read(TPA6130A2_REG_VERSION) &
@@ -404,10 +460,18 @@ static int tpa6130a2_probe(struct i2c_client *client,
                dev_warn(dev, "UNTESTED version detected (%d)\n", ret);
 
        /* Disable the chip */
-       tpa6130a2_power(0);
+       ret = tpa6130a2_power(0);
+       if (ret != 0)
+               goto err_power;
 
        return 0;
-fail:
+
+err_power:
+       regulator_bulk_free(ARRAY_SIZE(data->supplies), data->supplies);
+err_regulator:
+       if (data->power_gpio >= 0)
+               gpio_free(data->power_gpio);
+err_gpio:
        kfree(data);
        i2c_set_clientdata(tpa6130a2_client, NULL);
        tpa6130a2_client = NULL;
@@ -415,7 +479,7 @@ fail:
        return ret;
 }
 
-static int tpa6130a2_remove(struct i2c_client *client)
+static int __devexit tpa6130a2_remove(struct i2c_client *client)
 {
        struct tpa6130a2_data *data = i2c_get_clientdata(client);
 
@@ -423,6 +487,9 @@ static int tpa6130a2_remove(struct i2c_client *client)
 
        if (data->power_gpio >= 0)
                gpio_free(data->power_gpio);
+
+       regulator_bulk_free(ARRAY_SIZE(data->supplies), data->supplies);
+
        kfree(data);
        tpa6130a2_client = NULL;
 
index 2a27f7b56726ab951219fd36289d595ba92fdad7..6f5d4af200526ed5477f1870b9c48a048aa2865b 100644 (file)
@@ -55,7 +55,7 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
        0x0c, /* REG_ATXR1PGA           (0xB)   */
        0x00, /* REG_AVTXL2PGA          (0xC)   */
        0x00, /* REG_AVTXR2PGA          (0xD)   */
-       0x01, /* REG_AUDIO_IF           (0xE)   */
+       0x00, /* REG_AUDIO_IF           (0xE)   */
        0x00, /* REG_VOICE_IF           (0xF)   */
        0x00, /* REG_ARXR1PGA           (0x10)  */
        0x00, /* REG_ARXL1PGA           (0x11)  */
@@ -64,19 +64,19 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
        0x00, /* REG_VRXPGA             (0x14)  */
        0x00, /* REG_VSTPGA             (0x15)  */
        0x00, /* REG_VRX2ARXPGA         (0x16)  */
-       0x0c, /* REG_AVDAC_CTL          (0x17)  */
+       0x00, /* REG_AVDAC_CTL          (0x17)  */
        0x00, /* REG_ARX2VTXPGA         (0x18)  */
        0x00, /* REG_ARXL1_APGA_CTL     (0x19)  */
        0x00, /* REG_ARXR1_APGA_CTL     (0x1A)  */
-       0x4b, /* REG_ARXL2_APGA_CTL     (0x1B)  */
-       0x4b, /* REG_ARXR2_APGA_CTL     (0x1C)  */
+       0x4a, /* REG_ARXL2_APGA_CTL     (0x1B)  */
+       0x4a, /* REG_ARXR2_APGA_CTL     (0x1C)  */
        0x00, /* REG_ATX2ARXPGA         (0x1D)  */
        0x00, /* REG_BT_IF              (0x1E)  */
        0x00, /* REG_BTPGA              (0x1F)  */
        0x00, /* REG_BTSTPGA            (0x20)  */
        0x00, /* REG_EAR_CTL            (0x21)  */
-       0x24, /* REG_HS_SEL             (0x22)  */
-       0x0a, /* REG_HS_GAIN_SET        (0x23)  */
+       0x00, /* REG_HS_SEL             (0x22)  */
+       0x00, /* REG_HS_GAIN_SET        (0x23)  */
        0x00, /* REG_HS_POPN_SET        (0x24)  */
        0x00, /* REG_PREDL_CTL          (0x25)  */
        0x00, /* REG_PREDR_CTL          (0x26)  */
@@ -99,7 +99,7 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
        0x00, /* REG_I2S_RX_SCRAMBLE_H  (0x37)  */
        0x00, /* REG_I2S_RX_SCRAMBLE_M  (0x38)  */
        0x00, /* REG_I2S_RX_SCRAMBLE_L  (0x39)  */
-       0x16, /* REG_APLL_CTL           (0x3A)  */
+       0x06, /* REG_APLL_CTL           (0x3A)  */
        0x00, /* REG_DTMF_CTL           (0x3B)  */
        0x00, /* REG_DTMF_PGA_CTL2      (0x3C)  */
        0x00, /* REG_DTMF_PGA_CTL1      (0x3D)  */
@@ -1203,6 +1203,8 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
        SND_SOC_DAPM_SUPPLY("APLL Enable", SND_SOC_NOPM, 0, 0, apll_event,
                            SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD),
 
+       SND_SOC_DAPM_SUPPLY("AIF Enable", TWL4030_REG_AUDIO_IF, 0, 0, NULL, 0),
+
        /* Output MIXER controls */
        /* Earpiece */
        SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0,
@@ -1337,6 +1339,11 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"Digital L2 Playback Mixer", NULL, "APLL Enable"},
        {"Digital Voice Playback Mixer", NULL, "APLL Enable"},
 
+       {"Digital R1 Playback Mixer", NULL, "AIF Enable"},
+       {"Digital L1 Playback Mixer", NULL, "AIF Enable"},
+       {"Digital R2 Playback Mixer", NULL, "AIF Enable"},
+       {"Digital L2 Playback Mixer", NULL, "AIF Enable"},
+
        {"Analog L1 Playback Mixer", NULL, "Digital L1 Playback Mixer"},
        {"Analog R1 Playback Mixer", NULL, "Digital R1 Playback Mixer"},
        {"Analog L2 Playback Mixer", NULL, "Digital L2 Playback Mixer"},
@@ -1455,6 +1462,11 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"ADC Virtual Left2", NULL, "APLL Enable"},
        {"ADC Virtual Right2", NULL, "APLL Enable"},
 
+       {"ADC Virtual Left1", NULL, "AIF Enable"},
+       {"ADC Virtual Right1", NULL, "AIF Enable"},
+       {"ADC Virtual Left2", NULL, "AIF Enable"},
+       {"ADC Virtual Right2", NULL, "AIF Enable"},
+
        /* Analog bypass routes */
        {"Right1 Analog Loopback", "Switch", "Analog Right"},
        {"Left1 Analog Loopback", "Switch", "Analog Left"},
@@ -2152,8 +2164,6 @@ static int twl4030_soc_remove(struct platform_device *pdev)
        twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
        snd_soc_free_pcms(socdev);
        snd_soc_dapm_free(socdev);
-       kfree(codec->private_data);
-       kfree(codec);
 
        return 0;
 }
@@ -2192,7 +2202,7 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
        codec->write = twl4030_write;
        codec->set_bias_level = twl4030_set_bias_level;
        codec->dai = twl4030_dai;
-       codec->num_dai = ARRAY_SIZE(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);
@@ -2237,6 +2247,9 @@ static int __devexit twl4030_codec_remove(struct platform_device *pdev)
 {
        struct twl4030_priv *twl4030 = platform_get_drvdata(pdev);
 
+       snd_soc_unregister_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai));
+       snd_soc_unregister_codec(&twl4030->codec);
+       kfree(twl4030->codec.reg_cache);
        kfree(twl4030);
 
        twl4030_codec = NULL;
index dd6396ec9c79751e0fb8f6639d317d78f4e97434..f206d242ca3130a932bae30aa3074bd2fb28b98f 100644 (file)
@@ -25,7 +25,7 @@
 /* Register descriptions are here */
 #include <linux/mfd/twl4030-codec.h>
 
-/* Sgadow register used by the audio driver */
+/* Shadow register used by the audio driver */
 #define TWL4030_REG_SW_SHADOW          0x4A
 #define TWL4030_CACHEREGNUM    (TWL4030_REG_SW_SHADOW + 1)
 
diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c
new file mode 100644 (file)
index 0000000..217b026
--- /dev/null
@@ -0,0 +1,888 @@
+/*
+ * wm2000.c  --  WM2000 ALSA Soc Audio driver
+ *
+ * Copyright 2008-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.
+ *
+ * The download image for the WM2000 will be requested as
+ * 'wm2000_anc.bin' by default (overridable via platform data) at
+ * runtime and is expected to be in flat binary format.  This is
+ * generated by Wolfson configuration tools and includes
+ * system-specific callibration information.  If supplied as a
+ * sequence of ASCII-encoded hexidecimal bytes this can be converted
+ * into a flat binary with a command such as this on the command line:
+ *
+ * perl -e 'while (<>) { s/[\r\n]+// ; printf("%c", hex($_)); }'
+ *                 < file  > wm2000_anc.bin
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.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 <sound/wm2000.h>
+
+#include "wm2000.h"
+
+enum wm2000_anc_mode {
+       ANC_ACTIVE = 0,
+       ANC_BYPASS = 1,
+       ANC_STANDBY = 2,
+       ANC_OFF = 3,
+};
+
+struct wm2000_priv {
+       struct i2c_client *i2c;
+
+       enum wm2000_anc_mode anc_mode;
+
+       unsigned int anc_active:1;
+       unsigned int anc_eng_ena:1;
+       unsigned int spk_ena:1;
+
+       unsigned int mclk_div:1;
+       unsigned int speech_clarity:1;
+
+       int anc_download_size;
+       char *anc_download;
+};
+
+static struct i2c_client *wm2000_i2c;
+
+static int wm2000_write(struct i2c_client *i2c, unsigned int reg,
+                       unsigned int value)
+{
+       u8 data[3];
+       int ret;
+
+       data[0] = (reg >> 8) & 0xff;
+       data[1] = reg & 0xff;
+       data[2] = value & 0xff;
+
+       dev_vdbg(&i2c->dev, "write %x = %x\n", reg, value);
+
+       ret = i2c_master_send(i2c, data, 3);
+       if (ret == 3)
+               return 0;
+       if (ret < 0)
+               return ret;
+       else
+               return -EIO;
+}
+
+static unsigned int wm2000_read(struct i2c_client *i2c, unsigned int r)
+{
+       struct i2c_msg xfer[2];
+       u8 reg[2];
+       u8 data;
+       int ret;
+
+       /* Write register */
+       reg[0] = (r >> 8) & 0xff;
+       reg[1] = r & 0xff;
+       xfer[0].addr = i2c->addr;
+       xfer[0].flags = 0;
+       xfer[0].len = sizeof(reg);
+       xfer[0].buf = &reg[0];
+
+       /* Read data */
+       xfer[1].addr = i2c->addr;
+       xfer[1].flags = I2C_M_RD;
+       xfer[1].len = 1;
+       xfer[1].buf = &data;
+
+       ret = i2c_transfer(i2c->adapter, xfer, 2);
+       if (ret != 2) {
+               dev_err(&i2c->dev, "i2c_transfer() returned %d\n", ret);
+               return 0;
+       }
+
+       dev_vdbg(&i2c->dev, "read %x from %x\n", data, r);
+
+       return data;
+}
+
+static void wm2000_reset(struct wm2000_priv *wm2000)
+{
+       struct i2c_client *i2c = wm2000->i2c;
+
+       wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_ANC_ENG_CLR);
+       wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_RAM_CLR);
+       wm2000_write(i2c, WM2000_REG_ID1, 0);
+
+       wm2000->anc_mode = ANC_OFF;
+}
+
+static int wm2000_poll_bit(struct i2c_client *i2c,
+                          unsigned int reg, u8 mask, int timeout)
+{
+       int val;
+
+       val = wm2000_read(i2c, reg);
+
+       while (!(val & mask) && --timeout) {
+               msleep(1);
+               val = wm2000_read(i2c, reg);
+       }
+
+       if (timeout == 0)
+               return 0;
+       else
+               return 1;
+}
+
+static int wm2000_power_up(struct i2c_client *i2c, int analogue)
+{
+       struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
+       int ret, timeout;
+
+       BUG_ON(wm2000->anc_mode != ANC_OFF);
+
+       dev_dbg(&i2c->dev, "Beginning power up\n");
+
+       if (!wm2000->mclk_div) {
+               dev_dbg(&i2c->dev, "Disabling MCLK divider\n");
+               wm2000_write(i2c, WM2000_REG_SYS_CTL2,
+                            WM2000_MCLK_DIV2_ENA_CLR);
+       } else {
+               dev_dbg(&i2c->dev, "Enabling MCLK divider\n");
+               wm2000_write(i2c, WM2000_REG_SYS_CTL2,
+                            WM2000_MCLK_DIV2_ENA_SET);
+       }
+
+       wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_ANC_ENG_CLR);
+       wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_ANC_ENG_SET);
+
+       /* Wait for ANC engine to become ready */
+       if (!wm2000_poll_bit(i2c, WM2000_REG_ANC_STAT,
+                            WM2000_ANC_ENG_IDLE, 1)) {
+               dev_err(&i2c->dev, "ANC engine failed to reset\n");
+               return -ETIMEDOUT;
+       }
+
+       if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS,
+                            WM2000_STATUS_BOOT_COMPLETE, 1)) {
+               dev_err(&i2c->dev, "ANC engine failed to initialise\n");
+               return -ETIMEDOUT;
+       }
+
+       wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_RAM_SET);
+
+       /* Open code download of the data since it is the only bulk
+        * write we do. */
+       dev_dbg(&i2c->dev, "Downloading %d bytes\n",
+               wm2000->anc_download_size - 2);
+
+       ret = i2c_master_send(i2c, wm2000->anc_download,
+                             wm2000->anc_download_size);
+       if (ret < 0) {
+               dev_err(&i2c->dev, "i2c_transfer() failed: %d\n", ret);
+               return ret;
+       }
+       if (ret != wm2000->anc_download_size) {
+               dev_err(&i2c->dev, "i2c_transfer() failed, %d != %d\n",
+                       ret, wm2000->anc_download_size);
+               return -EIO;
+       }
+
+       dev_dbg(&i2c->dev, "Download complete\n");
+
+       if (analogue) {
+               timeout = 248;
+               wm2000_write(i2c, WM2000_REG_ANA_VMID_PU_TIME, timeout / 4);
+
+               wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL,
+                            WM2000_MODE_ANA_SEQ_INCLUDE |
+                            WM2000_MODE_MOUSE_ENABLE |
+                            WM2000_MODE_THERMAL_ENABLE);
+       } else {
+               timeout = 10;
+
+               wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL,
+                            WM2000_MODE_MOUSE_ENABLE |
+                            WM2000_MODE_THERMAL_ENABLE);
+       }
+
+       ret = wm2000_read(i2c, WM2000_REG_SPEECH_CLARITY);
+       if (wm2000->speech_clarity)
+               ret &= ~WM2000_SPEECH_CLARITY;
+       else
+               ret |= WM2000_SPEECH_CLARITY;
+       wm2000_write(i2c, WM2000_REG_SPEECH_CLARITY, ret);
+
+       wm2000_write(i2c, WM2000_REG_SYS_START0, 0x33);
+       wm2000_write(i2c, WM2000_REG_SYS_START1, 0x02);
+
+       wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_ANC_INT_N_CLR);
+
+       if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS,
+                            WM2000_STATUS_MOUSE_ACTIVE, timeout)) {
+               dev_err(&i2c->dev, "Timed out waiting for device after %dms\n",
+                       timeout * 10);
+               return -ETIMEDOUT;
+       }
+
+       dev_dbg(&i2c->dev, "ANC active\n");
+       if (analogue)
+               dev_dbg(&i2c->dev, "Analogue active\n");
+       wm2000->anc_mode = ANC_ACTIVE;
+
+       return 0;
+}
+
+static int wm2000_power_down(struct i2c_client *i2c, int analogue)
+{
+       struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
+       int timeout;
+
+       if (analogue) {
+               timeout = 248;
+               wm2000_write(i2c, WM2000_REG_ANA_VMID_PD_TIME, timeout / 4);
+               wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL,
+                            WM2000_MODE_ANA_SEQ_INCLUDE |
+                            WM2000_MODE_POWER_DOWN);
+       } else {
+               timeout = 10;
+               wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL,
+                            WM2000_MODE_POWER_DOWN);
+       }
+
+       if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS,
+                            WM2000_STATUS_POWER_DOWN_COMPLETE, timeout)) {
+               dev_err(&i2c->dev, "Timeout waiting for ANC power down\n");
+               return -ETIMEDOUT;
+       }
+
+       if (!wm2000_poll_bit(i2c, WM2000_REG_ANC_STAT,
+                            WM2000_ANC_ENG_IDLE, 1)) {
+               dev_err(&i2c->dev, "Timeout waiting for ANC engine idle\n");
+               return -ETIMEDOUT;
+       }
+
+       dev_dbg(&i2c->dev, "powered off\n");
+       wm2000->anc_mode = ANC_OFF;
+
+       return 0;
+}
+
+static int wm2000_enter_bypass(struct i2c_client *i2c, int analogue)
+{
+       struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
+
+       BUG_ON(wm2000->anc_mode != ANC_ACTIVE);
+
+       if (analogue) {
+               wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL,
+                            WM2000_MODE_ANA_SEQ_INCLUDE |
+                            WM2000_MODE_THERMAL_ENABLE |
+                            WM2000_MODE_BYPASS_ENTRY);
+       } else {
+               wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL,
+                            WM2000_MODE_THERMAL_ENABLE |
+                            WM2000_MODE_BYPASS_ENTRY);
+       }
+
+       if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS,
+                            WM2000_STATUS_ANC_DISABLED, 10)) {
+               dev_err(&i2c->dev, "Timeout waiting for ANC disable\n");
+               return -ETIMEDOUT;
+       }
+
+       if (!wm2000_poll_bit(i2c, WM2000_REG_ANC_STAT,
+                            WM2000_ANC_ENG_IDLE, 1)) {
+               dev_err(&i2c->dev, "Timeout waiting for ANC engine idle\n");
+               return -ETIMEDOUT;
+       }
+
+       wm2000_write(i2c, WM2000_REG_SYS_CTL1, WM2000_SYS_STBY);
+       wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_RAM_CLR);
+
+       wm2000->anc_mode = ANC_BYPASS;
+       dev_dbg(&i2c->dev, "bypass enabled\n");
+
+       return 0;
+}
+
+static int wm2000_exit_bypass(struct i2c_client *i2c, int analogue)
+{
+       struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
+
+       BUG_ON(wm2000->anc_mode != ANC_BYPASS);
+       
+       wm2000_write(i2c, WM2000_REG_SYS_CTL1, 0);
+
+       if (analogue) {
+               wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL,
+                            WM2000_MODE_ANA_SEQ_INCLUDE |
+                            WM2000_MODE_MOUSE_ENABLE |
+                            WM2000_MODE_THERMAL_ENABLE);
+       } else {
+               wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL,
+                            WM2000_MODE_MOUSE_ENABLE |
+                            WM2000_MODE_THERMAL_ENABLE);
+       }
+
+       wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_RAM_SET);
+       wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_ANC_INT_N_CLR);
+
+       if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS,
+                            WM2000_STATUS_MOUSE_ACTIVE, 10)) {
+               dev_err(&i2c->dev, "Timed out waiting for MOUSE\n");
+               return -ETIMEDOUT;
+       }
+
+       wm2000->anc_mode = ANC_ACTIVE;
+       dev_dbg(&i2c->dev, "MOUSE active\n");
+
+       return 0;
+}
+
+static int wm2000_enter_standby(struct i2c_client *i2c, int analogue)
+{
+       struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
+       int timeout;
+
+       BUG_ON(wm2000->anc_mode != ANC_ACTIVE);
+
+       if (analogue) {
+               timeout = 248;
+               wm2000_write(i2c, WM2000_REG_ANA_VMID_PD_TIME, timeout / 4);
+
+               wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL,
+                            WM2000_MODE_ANA_SEQ_INCLUDE |
+                            WM2000_MODE_THERMAL_ENABLE |
+                            WM2000_MODE_STANDBY_ENTRY);
+       } else {
+               timeout = 10;
+
+               wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL,
+                            WM2000_MODE_THERMAL_ENABLE |
+                            WM2000_MODE_STANDBY_ENTRY);
+       }
+
+       if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS,
+                            WM2000_STATUS_ANC_DISABLED, timeout)) {
+               dev_err(&i2c->dev,
+                       "Timed out waiting for ANC disable after 1ms\n");
+               return -ETIMEDOUT;
+       }
+
+       if (!wm2000_poll_bit(i2c, WM2000_REG_ANC_STAT, WM2000_ANC_ENG_IDLE,
+                            1)) {
+               dev_err(&i2c->dev,
+                       "Timed out waiting for standby after %dms\n",
+                       timeout * 10);
+               return -ETIMEDOUT;
+       }
+
+       wm2000_write(i2c, WM2000_REG_SYS_CTL1, WM2000_SYS_STBY);
+       wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_RAM_CLR);
+
+       wm2000->anc_mode = ANC_STANDBY;
+       dev_dbg(&i2c->dev, "standby\n");
+       if (analogue)
+               dev_dbg(&i2c->dev, "Analogue disabled\n");
+
+       return 0;
+}
+
+static int wm2000_exit_standby(struct i2c_client *i2c, int analogue)
+{
+       struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
+       int timeout;
+
+       BUG_ON(wm2000->anc_mode != ANC_STANDBY);
+
+       wm2000_write(i2c, WM2000_REG_SYS_CTL1, 0);
+
+       if (analogue) {
+               timeout = 248;
+               wm2000_write(i2c, WM2000_REG_ANA_VMID_PU_TIME, timeout / 4);
+
+               wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL,
+                            WM2000_MODE_ANA_SEQ_INCLUDE |
+                            WM2000_MODE_THERMAL_ENABLE |
+                            WM2000_MODE_MOUSE_ENABLE);
+       } else {
+               timeout = 10;
+
+               wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL,
+                            WM2000_MODE_THERMAL_ENABLE |
+                            WM2000_MODE_MOUSE_ENABLE);
+       }
+
+       wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_RAM_SET);
+       wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_ANC_INT_N_CLR);
+
+       if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS,
+                            WM2000_STATUS_MOUSE_ACTIVE, timeout)) {
+               dev_err(&i2c->dev, "Timed out waiting for MOUSE after %dms\n",
+                       timeout * 10);
+               return -ETIMEDOUT;
+       }
+
+       wm2000->anc_mode = ANC_ACTIVE;
+       dev_dbg(&i2c->dev, "MOUSE active\n");
+       if (analogue)
+               dev_dbg(&i2c->dev, "Analogue enabled\n");
+
+       return 0;
+}
+
+typedef int (*wm2000_mode_fn)(struct i2c_client *i2c, int analogue);
+
+static struct {
+       enum wm2000_anc_mode source;
+       enum wm2000_anc_mode dest;
+       int analogue;
+       wm2000_mode_fn step[2];
+} anc_transitions[] = {
+       {
+               .source = ANC_OFF,
+               .dest = ANC_ACTIVE,
+               .analogue = 1,
+               .step = {
+                       wm2000_power_up,
+               },
+       },
+       {
+               .source = ANC_OFF,
+               .dest = ANC_STANDBY,
+               .step = {
+                       wm2000_power_up,
+                       wm2000_enter_standby,
+               },
+       },
+       {
+               .source = ANC_OFF,
+               .dest = ANC_BYPASS,
+               .analogue = 1,
+               .step = {
+                       wm2000_power_up,
+                       wm2000_enter_bypass,
+               },
+       },
+       {
+               .source = ANC_ACTIVE,
+               .dest = ANC_BYPASS,
+               .analogue = 1,
+               .step = {
+                       wm2000_enter_bypass,
+               },
+       },
+       {
+               .source = ANC_ACTIVE,
+               .dest = ANC_STANDBY,
+               .analogue = 1,
+               .step = {
+                       wm2000_enter_standby,
+               },
+       },
+       {
+               .source = ANC_ACTIVE,
+               .dest = ANC_OFF,
+               .analogue = 1,
+               .step = {
+                       wm2000_power_down,
+               },
+       },
+       {
+               .source = ANC_BYPASS,
+               .dest = ANC_ACTIVE,
+               .analogue = 1,
+               .step = {
+                       wm2000_exit_bypass,
+               },
+       },
+       {
+               .source = ANC_BYPASS,
+               .dest = ANC_STANDBY,
+               .analogue = 1,
+               .step = {
+                       wm2000_exit_bypass,
+                       wm2000_enter_standby,
+               },
+       },
+       {
+               .source = ANC_BYPASS,
+               .dest = ANC_OFF,
+               .step = {
+                       wm2000_exit_bypass,
+                       wm2000_power_down,
+               },
+       },
+       {
+               .source = ANC_STANDBY,
+               .dest = ANC_ACTIVE,
+               .analogue = 1,
+               .step = {
+                       wm2000_exit_standby,
+               },
+       },
+       {
+               .source = ANC_STANDBY,
+               .dest = ANC_BYPASS,
+               .analogue = 1,
+               .step = {
+                       wm2000_exit_standby,
+                       wm2000_enter_bypass,
+               },
+       },
+       {
+               .source = ANC_STANDBY,
+               .dest = ANC_OFF,
+               .step = {
+                       wm2000_exit_standby,
+                       wm2000_power_down,
+               },
+       },
+};
+
+static int wm2000_anc_transition(struct wm2000_priv *wm2000,
+                                enum wm2000_anc_mode mode)
+{
+       struct i2c_client *i2c = wm2000->i2c;
+       int i, j;
+       int ret;
+
+       if (wm2000->anc_mode == mode)
+               return 0;
+
+       for (i = 0; i < ARRAY_SIZE(anc_transitions); i++)
+               if (anc_transitions[i].source == wm2000->anc_mode &&
+                   anc_transitions[i].dest == mode)
+                       break;
+       if (i == ARRAY_SIZE(anc_transitions)) {
+               dev_err(&i2c->dev, "No transition for %d->%d\n",
+                       wm2000->anc_mode, mode);
+               return -EINVAL;
+       }
+
+       for (j = 0; j < ARRAY_SIZE(anc_transitions[j].step); j++) {
+               if (!anc_transitions[i].step[j])
+                       break;
+               ret = anc_transitions[i].step[j](i2c,
+                                                anc_transitions[i].analogue);
+               if (ret != 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int wm2000_anc_set_mode(struct wm2000_priv *wm2000)
+{
+       struct i2c_client *i2c = wm2000->i2c;
+       enum wm2000_anc_mode mode;
+
+       if (wm2000->anc_eng_ena && wm2000->spk_ena)
+               if (wm2000->anc_active)
+                       mode = ANC_ACTIVE;
+               else
+                       mode = ANC_BYPASS;
+       else
+               mode = ANC_STANDBY;
+
+       dev_dbg(&i2c->dev, "Set mode %d (enabled %d, mute %d, active %d)\n",
+               mode, wm2000->anc_eng_ena, !wm2000->spk_ena,
+               wm2000->anc_active);
+
+       return wm2000_anc_transition(wm2000, mode);
+}
+
+static int wm2000_anc_mode_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct wm2000_priv *wm2000 = dev_get_drvdata(&wm2000_i2c->dev);
+
+       ucontrol->value.enumerated.item[0] = wm2000->anc_active;
+
+       return 0;
+}
+
+static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct wm2000_priv *wm2000 = dev_get_drvdata(&wm2000_i2c->dev);
+       int anc_active = ucontrol->value.enumerated.item[0];
+
+       if (anc_active > 1)
+               return -EINVAL;
+
+       wm2000->anc_active = anc_active;
+
+       return wm2000_anc_set_mode(wm2000);
+}
+
+static int wm2000_speaker_get(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct wm2000_priv *wm2000 = dev_get_drvdata(&wm2000_i2c->dev);
+
+       ucontrol->value.enumerated.item[0] = wm2000->spk_ena;
+
+       return 0;
+}
+
+static int wm2000_speaker_put(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct wm2000_priv *wm2000 = dev_get_drvdata(&wm2000_i2c->dev);
+       int val = ucontrol->value.enumerated.item[0];
+
+       if (val > 1)
+               return -EINVAL;
+
+       wm2000->spk_ena = val;
+
+       return wm2000_anc_set_mode(wm2000);
+}
+
+static const struct snd_kcontrol_new wm2000_controls[] = {
+       SOC_SINGLE_BOOL_EXT("WM2000 ANC Switch", 0,
+                           wm2000_anc_mode_get,
+                           wm2000_anc_mode_put),
+       SOC_SINGLE_BOOL_EXT("WM2000 Switch", 0,
+                           wm2000_speaker_get,
+                           wm2000_speaker_put),
+};
+
+static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w,
+                                 struct snd_kcontrol *kcontrol, int event)
+{
+       struct wm2000_priv *wm2000 = dev_get_drvdata(&wm2000_i2c->dev);
+
+       if (SND_SOC_DAPM_EVENT_ON(event))
+               wm2000->anc_eng_ena = 1;
+
+       if (SND_SOC_DAPM_EVENT_OFF(event))
+               wm2000->anc_eng_ena = 0;
+
+       return wm2000_anc_set_mode(wm2000);
+}
+
+static const struct snd_soc_dapm_widget wm2000_dapm_widgets[] = {
+/* Externally visible pins */
+SND_SOC_DAPM_OUTPUT("WM2000 SPKN"),
+SND_SOC_DAPM_OUTPUT("WM2000 SPKP"),
+
+SND_SOC_DAPM_INPUT("WM2000 LINN"),
+SND_SOC_DAPM_INPUT("WM2000 LINP"),
+
+SND_SOC_DAPM_PGA_E("ANC Engine", SND_SOC_NOPM, 0, 0, NULL, 0,
+                  wm2000_anc_power_event,
+                  SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+};
+
+/* Target, Path, Source */
+static const struct snd_soc_dapm_route audio_map[] = {
+       { "WM2000 SPKN", NULL, "ANC Engine" },
+       { "WM2000 SPKP", NULL, "ANC Engine" },
+       { "ANC Engine", NULL, "WM2000 LINN" },
+       { "ANC Engine", NULL, "WM2000 LINP" },
+};
+
+/* Called from the machine driver */
+int wm2000_add_controls(struct snd_soc_codec *codec)
+{
+       int ret;
+
+       if (!wm2000_i2c) {
+               pr_err("WM2000 not yet probed\n");
+               return -ENODEV;
+       }
+
+       ret = snd_soc_dapm_new_controls(codec, wm2000_dapm_widgets,
+                                       ARRAY_SIZE(wm2000_dapm_widgets));
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       if (ret < 0)
+               return ret;
+
+       return snd_soc_add_controls(codec, wm2000_controls,
+                       ARRAY_SIZE(wm2000_controls));
+}
+EXPORT_SYMBOL_GPL(wm2000_add_controls);
+
+static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *i2c_id)
+{
+       struct wm2000_priv *wm2000;
+       struct wm2000_platform_data *pdata;
+       const char *filename;
+       const struct firmware *fw;
+       int reg, ret;
+       u16 id;
+
+       if (wm2000_i2c) {
+               dev_err(&i2c->dev, "Another WM2000 is already registered\n");
+               return -EINVAL;
+       }
+
+       wm2000 = kzalloc(sizeof(struct wm2000_priv), GFP_KERNEL);
+       if (wm2000 == NULL) {
+               dev_err(&i2c->dev, "Unable to allocate private data\n");
+               return -ENOMEM;
+       }
+
+       /* Verify that this is a WM2000 */
+       reg = wm2000_read(i2c, WM2000_REG_ID1);
+       id = reg << 8;
+       reg = wm2000_read(i2c, WM2000_REG_ID2);
+       id |= reg & 0xff;
+
+       if (id != 0x2000) {
+               dev_err(&i2c->dev, "Device is not a WM2000 - ID %x\n", id);
+               ret = -ENODEV;
+               goto err;
+       }
+
+       reg = wm2000_read(i2c, WM2000_REG_REVISON);
+       dev_info(&i2c->dev, "revision %c\n", reg + 'A');
+
+       filename = "wm2000_anc.bin";
+       pdata = dev_get_platdata(&i2c->dev);
+       if (pdata) {
+               wm2000->mclk_div = pdata->mclkdiv2;
+               wm2000->speech_clarity = !pdata->speech_enh_disable;
+
+               if (pdata->download_file)
+                       filename = pdata->download_file;
+       }
+
+       ret = request_firmware(&fw, filename, &i2c->dev);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to acquire ANC data: %d\n", ret);
+               goto err;
+       }
+
+       /* Pre-cook the concatenation of the register address onto the image */
+       wm2000->anc_download_size = fw->size + 2;
+       wm2000->anc_download = kmalloc(wm2000->anc_download_size, GFP_KERNEL);
+       if (wm2000->anc_download == NULL) {
+               dev_err(&i2c->dev, "Out of memory\n");
+               ret = -ENOMEM;
+               goto err_fw;
+       }
+
+       wm2000->anc_download[0] = 0x80;
+       wm2000->anc_download[1] = 0x00;
+       memcpy(wm2000->anc_download + 2, fw->data, fw->size);
+
+       release_firmware(fw);
+
+       dev_set_drvdata(&i2c->dev, wm2000);
+       wm2000->anc_eng_ena = 1;
+       wm2000->i2c = i2c;
+
+       wm2000_reset(wm2000);
+
+       /* This will trigger a transition to standby mode by default */
+       wm2000_anc_set_mode(wm2000);    
+
+       wm2000_i2c = i2c;
+
+       return 0;
+
+err_fw:
+       release_firmware(fw);
+err:
+       kfree(wm2000);
+       return ret;
+}
+
+static __devexit int wm2000_i2c_remove(struct i2c_client *i2c)
+{
+       struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
+
+       wm2000_anc_transition(wm2000, ANC_OFF);
+
+       wm2000_i2c = NULL;
+       kfree(wm2000->anc_download);
+       kfree(wm2000);
+
+       return 0;
+}
+
+static void wm2000_i2c_shutdown(struct i2c_client *i2c)
+{
+       struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
+
+       wm2000_anc_transition(wm2000, ANC_OFF);
+}
+
+#ifdef CONFIG_PM
+static int wm2000_i2c_suspend(struct i2c_client *i2c, pm_message_t mesg)
+{
+       struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
+
+       return wm2000_anc_transition(wm2000, ANC_OFF);
+}
+
+static int wm2000_i2c_resume(struct i2c_client *i2c)
+{
+       struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
+
+       return wm2000_anc_set_mode(wm2000);
+}
+#else
+#define wm2000_i2c_suspend NULL
+#define wm2000_i2c_resume NULL
+#endif
+
+static const struct i2c_device_id wm2000_i2c_id[] = {
+       { "wm2000", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm2000_i2c_id);
+
+static struct i2c_driver wm2000_i2c_driver = {
+       .driver = {
+               .name = "wm2000",
+               .owner = THIS_MODULE,
+       },
+       .probe = wm2000_i2c_probe,
+       .remove = __devexit_p(wm2000_i2c_remove),
+       .suspend = wm2000_i2c_suspend,
+       .resume = wm2000_i2c_resume,
+       .shutdown = wm2000_i2c_shutdown,
+       .id_table = wm2000_i2c_id,
+};
+
+static int __init wm2000_init(void)
+{
+       return i2c_add_driver(&wm2000_i2c_driver);
+}
+module_init(wm2000_init);
+
+static void __exit wm2000_exit(void)
+{
+       i2c_del_driver(&wm2000_i2c_driver);
+}
+module_exit(wm2000_exit);
+
+MODULE_DESCRIPTION("ASoC WM2000 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm2000.h b/sound/soc/codecs/wm2000.h
new file mode 100644 (file)
index 0000000..c18e261
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * wm2000.h  --  WM2000 Soc Audio driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM2000_H
+#define _WM2000_H
+
+struct wm2000_setup_data {
+       unsigned short i2c_address;
+       int mclk_div;   /* Set to a non-zero value if MCLK_DIV_2 required */
+};
+
+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
+#define WM2000_REG_ANA_VMID_PD_TIME 0x8ff7
+#define WM2000_REG_ANA_VMID_PU_TIME 0x8ff8
+#define WM2000_REG_CAT_FLTR_INDX    0x8ff9
+#define WM2000_REG_CAT_GAIN_0       0x8ffa
+#define WM2000_REG_SYS_STATUS       0x8ffc
+#define WM2000_REG_SYS_MODE_CNTRL   0x8ffd
+#define WM2000_REG_SYS_START0       0x8ffe
+#define WM2000_REG_SYS_START1       0x8fff
+#define WM2000_REG_ID1              0xf000
+#define WM2000_REG_ID2              0xf001
+#define WM2000_REG_REVISON          0xf002
+#define WM2000_REG_SYS_CTL1         0xf003
+#define WM2000_REG_SYS_CTL2         0xf004
+#define WM2000_REG_ANC_STAT         0xf005
+#define WM2000_REG_IF_CTL           0xf006
+
+/* SPEECH_CLARITY */
+#define WM2000_SPEECH_CLARITY   0x01
+
+/* SYS_STATUS */
+#define WM2000_STATUS_MOUSE_ACTIVE              0x40
+#define WM2000_STATUS_CAT_FREQ_COMPLETE         0x20
+#define WM2000_STATUS_CAT_GAIN_COMPLETE         0x10
+#define WM2000_STATUS_THERMAL_SHUTDOWN_COMPLETE 0x08
+#define WM2000_STATUS_ANC_DISABLED              0x04
+#define WM2000_STATUS_POWER_DOWN_COMPLETE       0x02
+#define WM2000_STATUS_BOOT_COMPLETE             0x01
+
+/* SYS_MODE_CNTRL */
+#define WM2000_MODE_ANA_SEQ_INCLUDE 0x80
+#define WM2000_MODE_MOUSE_ENABLE    0x40
+#define WM2000_MODE_CAT_FREQ_ENABLE 0x20
+#define WM2000_MODE_CAT_GAIN_ENABLE 0x10
+#define WM2000_MODE_BYPASS_ENTRY    0x08
+#define WM2000_MODE_STANDBY_ENTRY   0x04
+#define WM2000_MODE_THERMAL_ENABLE  0x02
+#define WM2000_MODE_POWER_DOWN      0x01
+
+/* SYS_CTL1 */
+#define WM2000_SYS_STBY          0x01
+
+/* SYS_CTL2 */
+#define WM2000_MCLK_DIV2_ENA_CLR 0x80
+#define WM2000_MCLK_DIV2_ENA_SET 0x40
+#define WM2000_ANC_ENG_CLR       0x20
+#define WM2000_ANC_ENG_SET       0x10
+#define WM2000_ANC_INT_N_CLR     0x08
+#define WM2000_ANC_INT_N_SET     0x04
+#define WM2000_RAM_CLR           0x02
+#define WM2000_RAM_SET           0x01
+
+/* ANC_STAT */
+#define WM2000_ANC_ENG_IDLE      0x01
+
+#endif
index d8ffbd641d717d2e74ff38b134b5030338bd664f..63a254e293cae381d3f9c6c2d27ec985fd1d35ad 100644 (file)
@@ -44,23 +44,16 @@ struct snd_soc_dai wm8727_dai = {
 };
 EXPORT_SYMBOL_GPL(wm8727_dai);
 
+static struct snd_soc_codec *wm8727_codec;
+
 static int wm8727_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 = "WM8727";
-       codec->owner = THIS_MODULE;
-       codec->dai = &wm8727_dai;
-       codec->num_dai = 1;
-       socdev->card->codec = codec;
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
+       BUG_ON(!wm8727_codec);
+
+       socdev->card->codec = wm8727_codec;
 
        /* register pcms */
        ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
@@ -80,12 +73,9 @@ pcm_err:
 static int wm8727_soc_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);
+
        return 0;
 }
 
@@ -98,13 +88,55 @@ 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;
-       return snd_soc_register_dai(&wm8727_dai);
+
+       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;
+       }
+
+err_codec:
+       snd_soc_unregister_codec(codec);
+err:
+       kfree(codec);
+       return ret;
 }
 
 static int __devexit wm8727_platform_remove(struct platform_device *pdev)
 {
        snd_soc_unregister_dai(&wm8727_dai);
+       snd_soc_unregister_codec(platform_get_drvdata(pdev));
        return 0;
 }
 
index 3a497810f9391c36f9918f0a3c93e20dce5779e5..5a2619dbf283b8a6195eb912dae6fb2c9ae96149 100644 (file)
@@ -456,6 +456,9 @@ static int wm8731_resume(struct platform_device *pdev)
 
        /* Sync reg_cache with the hardware */
        for (i = 0; i < ARRAY_SIZE(wm8731_reg); i++) {
+               if (cache[i] == wm8731_reg[i])
+                       continue;
+
                data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
                data[1] = cache[i] & 0x00ff;
                codec->hw_write(codec->control_data, data, 2);
index d6850dacda29fbc9e36f3155fb9cd0557d59168e..c2444e7c848025524ada66f2ef8631112d15f908 100644 (file)
@@ -1507,10 +1507,6 @@ static int wm8753_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;
 
-       /* we only need to suspend if we are a valid card */
-       if (!codec->card)
-               return 0;
-
        wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
@@ -1523,10 +1519,6 @@ static int wm8753_resume(struct platform_device *pdev)
        u8 data[2];
        u16 *cache = codec->reg_cache;
 
-       /* we only need to resume if we are a valid card */
-       if (!codec->card)
-               return 0;
-
        /* Sync reg_cache with the hardware */
        for (i = 0; i < ARRAY_SIZE(wm8753_reg); i++) {
                if (i + 1 == WM8753_RESET)
index ab2c0da1809102396cc357ca78be1d3946a356a2..44e7d9d82f87d7b7e658272fc7fcedd67129c832 100644 (file)
@@ -406,6 +406,8 @@ static int wm8776_resume(struct platform_device *pdev)
 
        /* Sync reg_cache with the hardware */
        for (i = 0; i < ARRAY_SIZE(wm8776_reg); i++) {
+               if (cache[i] == wm8776_reg[i])
+                       continue;
                data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
                data[1] = cache[i] & 0x00ff;
                codec->hw_write(codec->control_data, data, 2);
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
new file mode 100644 (file)
index 0000000..593e47d
--- /dev/null
@@ -0,0 +1,2656 @@
+/*
+ * wm8904.c  --  WM8904 ALSA SoC Audio driver
+ *
+ * Copyright 2009 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/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.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 <sound/wm8904.h>
+
+#include "wm8904.h"
+
+static struct snd_soc_codec *wm8904_codec;
+struct snd_soc_codec_device soc_codec_dev_wm8904;
+
+enum wm8904_type {
+       WM8904,
+       WM8912,
+};
+
+#define WM8904_NUM_DCS_CHANNELS 4
+
+#define WM8904_NUM_SUPPLIES 5
+static const char *wm8904_supply_names[WM8904_NUM_SUPPLIES] = {
+       "DCVDD",
+       "DBVDD",
+       "AVDD",
+       "CPVDD",
+       "MICVDD",
+};
+
+/* codec private data */
+struct wm8904_priv {
+       struct snd_soc_codec codec;
+       u16 reg_cache[WM8904_MAX_REGISTER + 1];
+
+       enum wm8904_type devtype;
+
+       struct regulator_bulk_data supplies[WM8904_NUM_SUPPLIES];
+
+       struct wm8904_pdata *pdata;
+
+       int deemph;
+
+       /* Platform provided DRC configuration */
+       const char **drc_texts;
+       int drc_cfg;
+       struct soc_enum drc_enum;
+
+       /* Platform provided ReTune mobile configuration */
+       int num_retune_mobile_texts;
+       const char **retune_mobile_texts;
+       int retune_mobile_cfg;
+       struct soc_enum retune_mobile_enum;
+
+       /* FLL setup */
+       int fll_src;
+       int fll_fref;
+       int fll_fout;
+
+       /* Clocking configuration */
+       unsigned int mclk_rate;
+       int sysclk_src;
+       unsigned int sysclk_rate;
+
+       int tdm_width;
+       int tdm_slots;
+       int bclk;
+       int fs;
+
+       /* DC servo configuration - cached offset values */
+       int dcs_state[WM8904_NUM_DCS_CHANNELS];
+};
+
+static const u16 wm8904_reg[WM8904_MAX_REGISTER + 1] = {
+       0x8904,     /* R0   - SW Reset and ID */
+       0x0000,     /* R1   - Revision */
+       0x0000,     /* R2 */
+       0x0000,     /* R3 */
+       0x0018,     /* R4   - Bias Control 0 */
+       0x0000,     /* R5   - VMID Control 0 */
+       0x0000,     /* R6   - Mic Bias Control 0 */
+       0x0000,     /* R7   - Mic Bias Control 1 */
+       0x0001,     /* R8   - Analogue DAC 0 */
+       0x9696,     /* R9   - mic Filter Control */
+       0x0001,     /* R10  - Analogue ADC 0 */
+       0x0000,     /* R11 */
+       0x0000,     /* R12  - Power Management 0 */
+       0x0000,     /* R13 */
+       0x0000,     /* R14  - Power Management 2 */
+       0x0000,     /* R15  - Power Management 3 */
+       0x0000,     /* R16 */
+       0x0000,     /* R17 */
+       0x0000,     /* R18  - Power Management 6 */
+       0x0000,     /* R19 */
+       0x945E,     /* R20  - Clock Rates 0 */
+       0x0C05,     /* R21  - Clock Rates 1 */
+       0x0006,     /* R22  - Clock Rates 2 */
+       0x0000,     /* R23 */
+       0x0050,     /* R24  - Audio Interface 0 */
+       0x000A,     /* R25  - Audio Interface 1 */
+       0x00E4,     /* R26  - Audio Interface 2 */
+       0x0040,     /* R27  - Audio Interface 3 */
+       0x0000,     /* R28 */
+       0x0000,     /* R29 */
+       0x00C0,     /* R30  - DAC Digital Volume Left */
+       0x00C0,     /* R31  - DAC Digital Volume Right */
+       0x0000,     /* R32  - DAC Digital 0 */
+       0x0008,     /* R33  - DAC Digital 1 */
+       0x0000,     /* R34 */
+       0x0000,     /* R35 */
+       0x00C0,     /* R36  - ADC Digital Volume Left */
+       0x00C0,     /* R37  - ADC Digital Volume Right */
+       0x0010,     /* R38  - ADC Digital 0 */
+       0x0000,     /* R39  - Digital Microphone 0 */
+       0x01AF,     /* R40  - DRC 0 */
+       0x3248,     /* R41  - DRC 1 */
+       0x0000,     /* R42  - DRC 2 */
+       0x0000,     /* R43  - DRC 3 */
+       0x0085,     /* R44  - Analogue Left Input 0 */
+       0x0085,     /* R45  - Analogue Right Input 0 */
+       0x0044,     /* R46  - Analogue Left Input 1 */
+       0x0044,     /* R47  - Analogue Right Input 1 */
+       0x0000,     /* R48 */
+       0x0000,     /* R49 */
+       0x0000,     /* R50 */
+       0x0000,     /* R51 */
+       0x0000,     /* R52 */
+       0x0000,     /* R53 */
+       0x0000,     /* R54 */
+       0x0000,     /* R55 */
+       0x0000,     /* R56 */
+       0x002D,     /* R57  - Analogue OUT1 Left */
+       0x002D,     /* R58  - Analogue OUT1 Right */
+       0x0039,     /* R59  - Analogue OUT2 Left */
+       0x0039,     /* R60  - Analogue OUT2 Right */
+       0x0000,     /* R61  - Analogue OUT12 ZC */
+       0x0000,     /* R62 */
+       0x0000,     /* R63 */
+       0x0000,     /* R64 */
+       0x0000,     /* R65 */
+       0x0000,     /* R66 */
+       0x0000,     /* R67  - DC Servo 0 */
+       0x0000,     /* R68  - DC Servo 1 */
+       0xAAAA,     /* R69  - DC Servo 2 */
+       0x0000,     /* R70 */
+       0xAAAA,     /* R71  - DC Servo 4 */
+       0xAAAA,     /* R72  - DC Servo 5 */
+       0x0000,     /* R73  - DC Servo 6 */
+       0x0000,     /* R74  - DC Servo 7 */
+       0x0000,     /* R75  - DC Servo 8 */
+       0x0000,     /* R76  - DC Servo 9 */
+       0x0000,     /* R77  - DC Servo Readback 0 */
+       0x0000,     /* R78 */
+       0x0000,     /* R79 */
+       0x0000,     /* R80 */
+       0x0000,     /* R81 */
+       0x0000,     /* R82 */
+       0x0000,     /* R83 */
+       0x0000,     /* R84 */
+       0x0000,     /* R85 */
+       0x0000,     /* R86 */
+       0x0000,     /* R87 */
+       0x0000,     /* R88 */
+       0x0000,     /* R89 */
+       0x0000,     /* R90  - Analogue HP 0 */
+       0x0000,     /* R91 */
+       0x0000,     /* R92 */
+       0x0000,     /* R93 */
+       0x0000,     /* R94  - Analogue Lineout 0 */
+       0x0000,     /* R95 */
+       0x0000,     /* R96 */
+       0x0000,     /* R97 */
+       0x0000,     /* R98  - Charge Pump 0 */
+       0x0000,     /* R99 */
+       0x0000,     /* R100 */
+       0x0000,     /* R101 */
+       0x0000,     /* R102 */
+       0x0000,     /* R103 */
+       0x0004,     /* R104 - Class W 0 */
+       0x0000,     /* R105 */
+       0x0000,     /* R106 */
+       0x0000,     /* R107 */
+       0x0000,     /* R108 - Write Sequencer 0 */
+       0x0000,     /* R109 - Write Sequencer 1 */
+       0x0000,     /* R110 - Write Sequencer 2 */
+       0x0000,     /* R111 - Write Sequencer 3 */
+       0x0000,     /* R112 - Write Sequencer 4 */
+       0x0000,     /* R113 */
+       0x0000,     /* R114 */
+       0x0000,     /* R115 */
+       0x0000,     /* R116 - FLL Control 1 */
+       0x0007,     /* R117 - FLL Control 2 */
+       0x0000,     /* R118 - FLL Control 3 */
+       0x2EE0,     /* R119 - FLL Control 4 */
+       0x0004,     /* R120 - FLL Control 5 */
+       0x0014,     /* R121 - GPIO Control 1 */
+       0x0010,     /* R122 - GPIO Control 2 */
+       0x0010,     /* R123 - GPIO Control 3 */
+       0x0000,     /* R124 - GPIO Control 4 */
+       0x0000,     /* R125 */
+       0x0000,     /* R126 - Digital Pulls */
+       0x0000,     /* R127 - Interrupt Status */
+       0xFFFF,     /* R128 - Interrupt Status Mask */
+       0x0000,     /* R129 - Interrupt Polarity */
+       0x0000,     /* R130 - Interrupt Debounce */
+       0x0000,     /* R131 */
+       0x0000,     /* R132 */
+       0x0000,     /* R133 */
+       0x0000,     /* R134 - EQ1 */
+       0x000C,     /* R135 - EQ2 */
+       0x000C,     /* R136 - EQ3 */
+       0x000C,     /* R137 - EQ4 */
+       0x000C,     /* R138 - EQ5 */
+       0x000C,     /* R139 - EQ6 */
+       0x0FCA,     /* R140 - EQ7 */
+       0x0400,     /* R141 - EQ8 */
+       0x00D8,     /* R142 - EQ9 */
+       0x1EB5,     /* R143 - EQ10 */
+       0xF145,     /* R144 - EQ11 */
+       0x0B75,     /* R145 - EQ12 */
+       0x01C5,     /* R146 - EQ13 */
+       0x1C58,     /* R147 - EQ14 */
+       0xF373,     /* R148 - EQ15 */
+       0x0A54,     /* R149 - EQ16 */
+       0x0558,     /* R150 - EQ17 */
+       0x168E,     /* R151 - EQ18 */
+       0xF829,     /* R152 - EQ19 */
+       0x07AD,     /* R153 - EQ20 */
+       0x1103,     /* R154 - EQ21 */
+       0x0564,     /* R155 - EQ22 */
+       0x0559,     /* R156 - EQ23 */
+       0x4000,     /* R157 - EQ24 */
+       0x0000,     /* R158 */
+       0x0000,     /* R159 */
+       0x0000,     /* R160 */
+       0x0000,     /* R161 - Control Interface Test 1 */
+       0x0000,     /* R162 */
+       0x0000,     /* R163 */
+       0x0000,     /* R164 */
+       0x0000,     /* R165 */
+       0x0000,     /* R166 */
+       0x0000,     /* R167 */
+       0x0000,     /* R168 */
+       0x0000,     /* R169 */
+       0x0000,     /* R170 */
+       0x0000,     /* R171 */
+       0x0000,     /* R172 */
+       0x0000,     /* R173 */
+       0x0000,     /* R174 */
+       0x0000,     /* R175 */
+       0x0000,     /* R176 */
+       0x0000,     /* R177 */
+       0x0000,     /* R178 */
+       0x0000,     /* R179 */
+       0x0000,     /* R180 */
+       0x0000,     /* R181 */
+       0x0000,     /* R182 */
+       0x0000,     /* R183 */
+       0x0000,     /* R184 */
+       0x0000,     /* R185 */
+       0x0000,     /* R186 */
+       0x0000,     /* R187 */
+       0x0000,     /* R188 */
+       0x0000,     /* R189 */
+       0x0000,     /* R190 */
+       0x0000,     /* R191 */
+       0x0000,     /* R192 */
+       0x0000,     /* R193 */
+       0x0000,     /* R194 */
+       0x0000,     /* R195 */
+       0x0000,     /* R196 */
+       0x0000,     /* R197 */
+       0x0000,     /* R198 */
+       0x0000,     /* R199 */
+       0x0000,     /* R200 */
+       0x0000,     /* R201 */
+       0x0000,     /* R202 */
+       0x0000,     /* R203 */
+       0x0000,     /* R204 - Analogue Output Bias 0 */
+       0x0000,     /* R205 */
+       0x0000,     /* R206 */
+       0x0000,     /* R207 */
+       0x0000,     /* R208 */
+       0x0000,     /* R209 */
+       0x0000,     /* R210 */
+       0x0000,     /* R211 */
+       0x0000,     /* R212 */
+       0x0000,     /* R213 */
+       0x0000,     /* R214 */
+       0x0000,     /* R215 */
+       0x0000,     /* R216 */
+       0x0000,     /* R217 */
+       0x0000,     /* R218 */
+       0x0000,     /* R219 */
+       0x0000,     /* R220 */
+       0x0000,     /* R221 */
+       0x0000,     /* R222 */
+       0x0000,     /* R223 */
+       0x0000,     /* R224 */
+       0x0000,     /* R225 */
+       0x0000,     /* R226 */
+       0x0000,     /* R227 */
+       0x0000,     /* R228 */
+       0x0000,     /* R229 */
+       0x0000,     /* R230 */
+       0x0000,     /* R231 */
+       0x0000,     /* R232 */
+       0x0000,     /* R233 */
+       0x0000,     /* R234 */
+       0x0000,     /* R235 */
+       0x0000,     /* R236 */
+       0x0000,     /* R237 */
+       0x0000,     /* R238 */
+       0x0000,     /* R239 */
+       0x0000,     /* R240 */
+       0x0000,     /* R241 */
+       0x0000,     /* R242 */
+       0x0000,     /* R243 */
+       0x0000,     /* R244 */
+       0x0000,     /* R245 */
+       0x0000,     /* R246 */
+       0x0000,     /* R247 - FLL NCO Test 0 */
+       0x0019,     /* R248 - FLL NCO Test 1 */
+};
+
+static struct {
+       int readable;
+       int writable;
+       int vol;
+} wm8904_access[] = {
+       { 0xFFFF, 0xFFFF, 1 }, /* R0   - SW Reset and ID */
+       { 0x0000, 0x0000, 0 }, /* R1   - Revision */
+       { 0x0000, 0x0000, 0 }, /* R2 */
+       { 0x0000, 0x0000, 0 }, /* R3 */
+       { 0x001F, 0x001F, 0 }, /* R4   - Bias Control 0 */
+       { 0x0047, 0x0047, 0 }, /* R5   - VMID Control 0 */
+       { 0x007F, 0x007F, 0 }, /* R6   - Mic Bias Control 0 */
+       { 0xC007, 0xC007, 0 }, /* R7   - Mic Bias Control 1 */
+       { 0x001E, 0x001E, 0 }, /* R8   - Analogue DAC 0 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R9   - mic Filter Control */
+       { 0x0001, 0x0001, 0 }, /* R10  - Analogue ADC 0 */
+       { 0x0000, 0x0000, 0 }, /* R11 */
+       { 0x0003, 0x0003, 0 }, /* R12  - Power Management 0 */
+       { 0x0000, 0x0000, 0 }, /* R13 */
+       { 0x0003, 0x0003, 0 }, /* R14  - Power Management 2 */
+       { 0x0003, 0x0003, 0 }, /* R15  - Power Management 3 */
+       { 0x0000, 0x0000, 0 }, /* R16 */
+       { 0x0000, 0x0000, 0 }, /* R17 */
+       { 0x000F, 0x000F, 0 }, /* R18  - Power Management 6 */
+       { 0x0000, 0x0000, 0 }, /* R19 */
+       { 0x7001, 0x7001, 0 }, /* R20  - Clock Rates 0 */
+       { 0x3C07, 0x3C07, 0 }, /* R21  - Clock Rates 1 */
+       { 0xD00F, 0xD00F, 0 }, /* R22  - Clock Rates 2 */
+       { 0x0000, 0x0000, 0 }, /* R23 */
+       { 0x1FFF, 0x1FFF, 0 }, /* R24  - Audio Interface 0 */
+       { 0x3DDF, 0x3DDF, 0 }, /* R25  - Audio Interface 1 */
+       { 0x0F1F, 0x0F1F, 0 }, /* R26  - Audio Interface 2 */
+       { 0x0FFF, 0x0FFF, 0 }, /* R27  - Audio Interface 3 */
+       { 0x0000, 0x0000, 0 }, /* R28 */
+       { 0x0000, 0x0000, 0 }, /* R29 */
+       { 0x00FF, 0x01FF, 0 }, /* R30  - DAC Digital Volume Left */
+       { 0x00FF, 0x01FF, 0 }, /* R31  - DAC Digital Volume Right */
+       { 0x0FFF, 0x0FFF, 0 }, /* R32  - DAC Digital 0 */
+       { 0x1E4E, 0x1E4E, 0 }, /* R33  - DAC Digital 1 */
+       { 0x0000, 0x0000, 0 }, /* R34 */
+       { 0x0000, 0x0000, 0 }, /* R35 */
+       { 0x00FF, 0x01FF, 0 }, /* R36  - ADC Digital Volume Left */
+       { 0x00FF, 0x01FF, 0 }, /* R37  - ADC Digital Volume Right */
+       { 0x0073, 0x0073, 0 }, /* R38  - ADC Digital 0 */
+       { 0x1800, 0x1800, 0 }, /* R39  - Digital Microphone 0 */
+       { 0xDFEF, 0xDFEF, 0 }, /* R40  - DRC 0 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R41  - DRC 1 */
+       { 0x003F, 0x003F, 0 }, /* R42  - DRC 2 */
+       { 0x07FF, 0x07FF, 0 }, /* R43  - DRC 3 */
+       { 0x009F, 0x009F, 0 }, /* R44  - Analogue Left Input 0 */
+       { 0x009F, 0x009F, 0 }, /* R45  - Analogue Right Input 0 */
+       { 0x007F, 0x007F, 0 }, /* R46  - Analogue Left Input 1 */
+       { 0x007F, 0x007F, 0 }, /* R47  - Analogue Right Input 1 */
+       { 0x0000, 0x0000, 0 }, /* R48 */
+       { 0x0000, 0x0000, 0 }, /* R49 */
+       { 0x0000, 0x0000, 0 }, /* R50 */
+       { 0x0000, 0x0000, 0 }, /* R51 */
+       { 0x0000, 0x0000, 0 }, /* R52 */
+       { 0x0000, 0x0000, 0 }, /* R53 */
+       { 0x0000, 0x0000, 0 }, /* R54 */
+       { 0x0000, 0x0000, 0 }, /* R55 */
+       { 0x0000, 0x0000, 0 }, /* R56 */
+       { 0x017F, 0x01FF, 0 }, /* R57  - Analogue OUT1 Left */
+       { 0x017F, 0x01FF, 0 }, /* R58  - Analogue OUT1 Right */
+       { 0x017F, 0x01FF, 0 }, /* R59  - Analogue OUT2 Left */
+       { 0x017F, 0x01FF, 0 }, /* R60  - Analogue OUT2 Right */
+       { 0x000F, 0x000F, 0 }, /* R61  - Analogue OUT12 ZC */
+       { 0x0000, 0x0000, 0 }, /* R62 */
+       { 0x0000, 0x0000, 0 }, /* R63 */
+       { 0x0000, 0x0000, 0 }, /* R64 */
+       { 0x0000, 0x0000, 0 }, /* R65 */
+       { 0x0000, 0x0000, 0 }, /* R66 */
+       { 0x000F, 0x000F, 0 }, /* R67  - DC Servo 0 */
+       { 0xFFFF, 0xFFFF, 1 }, /* R68  - DC Servo 1 */
+       { 0x0F0F, 0x0F0F, 0 }, /* R69  - DC Servo 2 */
+       { 0x0000, 0x0000, 0 }, /* R70 */
+       { 0x007F, 0x007F, 0 }, /* R71  - DC Servo 4 */
+       { 0x007F, 0x007F, 0 }, /* R72  - DC Servo 5 */
+       { 0x00FF, 0x00FF, 1 }, /* R73  - DC Servo 6 */
+       { 0x00FF, 0x00FF, 1 }, /* R74  - DC Servo 7 */
+       { 0x00FF, 0x00FF, 1 }, /* R75  - DC Servo 8 */
+       { 0x00FF, 0x00FF, 1 }, /* R76  - DC Servo 9 */
+       { 0x0FFF, 0x0000, 1 }, /* R77  - DC Servo Readback 0 */
+       { 0x0000, 0x0000, 0 }, /* R78 */
+       { 0x0000, 0x0000, 0 }, /* R79 */
+       { 0x0000, 0x0000, 0 }, /* R80 */
+       { 0x0000, 0x0000, 0 }, /* R81 */
+       { 0x0000, 0x0000, 0 }, /* R82 */
+       { 0x0000, 0x0000, 0 }, /* R83 */
+       { 0x0000, 0x0000, 0 }, /* R84 */
+       { 0x0000, 0x0000, 0 }, /* R85 */
+       { 0x0000, 0x0000, 0 }, /* R86 */
+       { 0x0000, 0x0000, 0 }, /* R87 */
+       { 0x0000, 0x0000, 0 }, /* R88 */
+       { 0x0000, 0x0000, 0 }, /* R89 */
+       { 0x00FF, 0x00FF, 0 }, /* R90  - Analogue HP 0 */
+       { 0x0000, 0x0000, 0 }, /* R91 */
+       { 0x0000, 0x0000, 0 }, /* R92 */
+       { 0x0000, 0x0000, 0 }, /* R93 */
+       { 0x00FF, 0x00FF, 0 }, /* R94  - Analogue Lineout 0 */
+       { 0x0000, 0x0000, 0 }, /* R95 */
+       { 0x0000, 0x0000, 0 }, /* R96 */
+       { 0x0000, 0x0000, 0 }, /* R97 */
+       { 0x0001, 0x0001, 0 }, /* R98  - Charge Pump 0 */
+       { 0x0000, 0x0000, 0 }, /* R99 */
+       { 0x0000, 0x0000, 0 }, /* R100 */
+       { 0x0000, 0x0000, 0 }, /* R101 */
+       { 0x0000, 0x0000, 0 }, /* R102 */
+       { 0x0000, 0x0000, 0 }, /* R103 */
+       { 0x0001, 0x0001, 0 }, /* R104 - Class W 0 */
+       { 0x0000, 0x0000, 0 }, /* R105 */
+       { 0x0000, 0x0000, 0 }, /* R106 */
+       { 0x0000, 0x0000, 0 }, /* R107 */
+       { 0x011F, 0x011F, 0 }, /* R108 - Write Sequencer 0 */
+       { 0x7FFF, 0x7FFF, 0 }, /* R109 - Write Sequencer 1 */
+       { 0x4FFF, 0x4FFF, 0 }, /* R110 - Write Sequencer 2 */
+       { 0x003F, 0x033F, 0 }, /* R111 - Write Sequencer 3 */
+       { 0x03F1, 0x0000, 0 }, /* R112 - Write Sequencer 4 */
+       { 0x0000, 0x0000, 0 }, /* R113 */
+       { 0x0000, 0x0000, 0 }, /* R114 */
+       { 0x0000, 0x0000, 0 }, /* R115 */
+       { 0x0007, 0x0007, 0 }, /* R116 - FLL Control 1 */
+       { 0x3F77, 0x3F77, 0 }, /* R117 - FLL Control 2 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R118 - FLL Control 3 */
+       { 0x7FEF, 0x7FEF, 0 }, /* R119 - FLL Control 4 */
+       { 0x001B, 0x001B, 0 }, /* R120 - FLL Control 5 */
+       { 0x003F, 0x003F, 0 }, /* R121 - GPIO Control 1 */
+       { 0x003F, 0x003F, 0 }, /* R122 - GPIO Control 2 */
+       { 0x003F, 0x003F, 0 }, /* R123 - GPIO Control 3 */
+       { 0x038F, 0x038F, 0 }, /* R124 - GPIO Control 4 */
+       { 0x0000, 0x0000, 0 }, /* R125 */
+       { 0x00FF, 0x00FF, 0 }, /* R126 - Digital Pulls */
+       { 0x07FF, 0x03FF, 1 }, /* R127 - Interrupt Status */
+       { 0x03FF, 0x03FF, 0 }, /* R128 - Interrupt Status Mask */
+       { 0x03FF, 0x03FF, 0 }, /* R129 - Interrupt Polarity */
+       { 0x03FF, 0x03FF, 0 }, /* R130 - Interrupt Debounce */
+       { 0x0000, 0x0000, 0 }, /* R131 */
+       { 0x0000, 0x0000, 0 }, /* R132 */
+       { 0x0000, 0x0000, 0 }, /* R133 */
+       { 0x0001, 0x0001, 0 }, /* R134 - EQ1 */
+       { 0x001F, 0x001F, 0 }, /* R135 - EQ2 */
+       { 0x001F, 0x001F, 0 }, /* R136 - EQ3 */
+       { 0x001F, 0x001F, 0 }, /* R137 - EQ4 */
+       { 0x001F, 0x001F, 0 }, /* R138 - EQ5 */
+       { 0x001F, 0x001F, 0 }, /* R139 - EQ6 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R140 - EQ7 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R141 - EQ8 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R142 - EQ9 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R143 - EQ10 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R144 - EQ11 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R145 - EQ12 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R146 - EQ13 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R147 - EQ14 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R148 - EQ15 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R149 - EQ16 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R150 - EQ17 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R151wm8523_dai - EQ18 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R152 - EQ19 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R153 - EQ20 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R154 - EQ21 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R155 - EQ22 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R156 - EQ23 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R157 - EQ24 */
+       { 0x0000, 0x0000, 0 }, /* R158 */
+       { 0x0000, 0x0000, 0 }, /* R159 */
+       { 0x0000, 0x0000, 0 }, /* R160 */
+       { 0x0002, 0x0002, 0 }, /* R161 - Control Interface Test 1 */
+       { 0x0000, 0x0000, 0 }, /* R162 */
+       { 0x0000, 0x0000, 0 }, /* R163 */
+       { 0x0000, 0x0000, 0 }, /* R164 */
+       { 0x0000, 0x0000, 0 }, /* R165 */
+       { 0x0000, 0x0000, 0 }, /* R166 */
+       { 0x0000, 0x0000, 0 }, /* R167 */
+       { 0x0000, 0x0000, 0 }, /* R168 */
+       { 0x0000, 0x0000, 0 }, /* R169 */
+       { 0x0000, 0x0000, 0 }, /* R170 */
+       { 0x0000, 0x0000, 0 }, /* R171 */
+       { 0x0000, 0x0000, 0 }, /* R172 */
+       { 0x0000, 0x0000, 0 }, /* R173 */
+       { 0x0000, 0x0000, 0 }, /* R174 */
+       { 0x0000, 0x0000, 0 }, /* R175 */
+       { 0x0000, 0x0000, 0 }, /* R176 */
+       { 0x0000, 0x0000, 0 }, /* R177 */
+       { 0x0000, 0x0000, 0 }, /* R178 */
+       { 0x0000, 0x0000, 0 }, /* R179 */
+       { 0x0000, 0x0000, 0 }, /* R180 */
+       { 0x0000, 0x0000, 0 }, /* R181 */
+       { 0x0000, 0x0000, 0 }, /* R182 */
+       { 0x0000, 0x0000, 0 }, /* R183 */
+       { 0x0000, 0x0000, 0 }, /* R184 */
+       { 0x0000, 0x0000, 0 }, /* R185 */
+       { 0x0000, 0x0000, 0 }, /* R186 */
+       { 0x0000, 0x0000, 0 }, /* R187 */
+       { 0x0000, 0x0000, 0 }, /* R188 */
+       { 0x0000, 0x0000, 0 }, /* R189 */
+       { 0x0000, 0x0000, 0 }, /* R190 */
+       { 0x0000, 0x0000, 0 }, /* R191 */
+       { 0x0000, 0x0000, 0 }, /* R192 */
+       { 0x0000, 0x0000, 0 }, /* R193 */
+       { 0x0000, 0x0000, 0 }, /* R194 */
+       { 0x0000, 0x0000, 0 }, /* R195 */
+       { 0x0000, 0x0000, 0 }, /* R196 */
+       { 0x0000, 0x0000, 0 }, /* R197 */
+       { 0x0000, 0x0000, 0 }, /* R198 */
+       { 0x0000, 0x0000, 0 }, /* R199 */
+       { 0x0000, 0x0000, 0 }, /* R200 */
+       { 0x0000, 0x0000, 0 }, /* R201 */
+       { 0x0000, 0x0000, 0 }, /* R202 */
+       { 0x0000, 0x0000, 0 }, /* R203 */
+       { 0x0070, 0x0070, 0 }, /* R204 - Analogue Output Bias 0 */
+       { 0x0000, 0x0000, 0 }, /* R205 */
+       { 0x0000, 0x0000, 0 }, /* R206 */
+       { 0x0000, 0x0000, 0 }, /* R207 */
+       { 0x0000, 0x0000, 0 }, /* R208 */
+       { 0x0000, 0x0000, 0 }, /* R209 */
+       { 0x0000, 0x0000, 0 }, /* R210 */
+       { 0x0000, 0x0000, 0 }, /* R211 */
+       { 0x0000, 0x0000, 0 }, /* R212 */
+       { 0x0000, 0x0000, 0 }, /* R213 */
+       { 0x0000, 0x0000, 0 }, /* R214 */
+       { 0x0000, 0x0000, 0 }, /* R215 */
+       { 0x0000, 0x0000, 0 }, /* R216 */
+       { 0x0000, 0x0000, 0 }, /* R217 */
+       { 0x0000, 0x0000, 0 }, /* R218 */
+       { 0x0000, 0x0000, 0 }, /* R219 */
+       { 0x0000, 0x0000, 0 }, /* R220 */
+       { 0x0000, 0x0000, 0 }, /* R221 */
+       { 0x0000, 0x0000, 0 }, /* R222 */
+       { 0x0000, 0x0000, 0 }, /* R223 */
+       { 0x0000, 0x0000, 0 }, /* R224 */
+       { 0x0000, 0x0000, 0 }, /* R225 */
+       { 0x0000, 0x0000, 0 }, /* R226 */
+       { 0x0000, 0x0000, 0 }, /* R227 */
+       { 0x0000, 0x0000, 0 }, /* R228 */
+       { 0x0000, 0x0000, 0 }, /* R229 */
+       { 0x0000, 0x0000, 0 }, /* R230 */
+       { 0x0000, 0x0000, 0 }, /* R231 */
+       { 0x0000, 0x0000, 0 }, /* R232 */
+       { 0x0000, 0x0000, 0 }, /* R233 */
+       { 0x0000, 0x0000, 0 }, /* R234 */
+       { 0x0000, 0x0000, 0 }, /* R235 */
+       { 0x0000, 0x0000, 0 }, /* R236 */
+       { 0x0000, 0x0000, 0 }, /* R237 */
+       { 0x0000, 0x0000, 0 }, /* R238 */
+       { 0x0000, 0x0000, 0 }, /* R239 */
+       { 0x0000, 0x0000, 0 }, /* R240 */
+       { 0x0000, 0x0000, 0 }, /* R241 */
+       { 0x0000, 0x0000, 0 }, /* R242 */
+       { 0x0000, 0x0000, 0 }, /* R243 */
+       { 0x0000, 0x0000, 0 }, /* R244 */
+       { 0x0000, 0x0000, 0 }, /* R245 */
+       { 0x0000, 0x0000, 0 }, /* R246 */
+       { 0x0001, 0x0001, 0 }, /* R247 - FLL NCO Test 0 */
+       { 0x003F, 0x003F, 0 }, /* R248 - FLL NCO Test 1 */
+};
+
+static int wm8904_volatile_register(unsigned int reg)
+{
+       return wm8904_access[reg].vol;
+}
+
+static int wm8904_reset(struct snd_soc_codec *codec)
+{
+       return snd_soc_write(codec, WM8904_SW_RESET_AND_ID, 0);
+}
+
+static int wm8904_configure_clocking(struct snd_soc_codec *codec)
+{
+       struct wm8904_priv *wm8904 = codec->private_data;
+       unsigned int clock0, clock2, rate;
+
+       /* Gate the clock while we're updating to avoid misclocking */
+       clock2 = snd_soc_read(codec, WM8904_CLOCK_RATES_2);
+       snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2,
+                           WM8904_SYSCLK_SRC, 0);
+
+       /* This should be done on init() for bypass paths */
+       switch (wm8904->sysclk_src) {
+       case WM8904_CLK_MCLK:
+               dev_dbg(codec->dev, "Using %dHz MCLK\n", wm8904->mclk_rate);
+
+               clock2 &= ~WM8904_SYSCLK_SRC;
+               rate = wm8904->mclk_rate;
+
+               /* Ensure the FLL is stopped */
+               snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
+                                   WM8904_FLL_OSC_ENA | WM8904_FLL_ENA, 0);
+               break;
+
+       case WM8904_CLK_FLL:
+               dev_dbg(codec->dev, "Using %dHz FLL clock\n",
+                       wm8904->fll_fout);
+
+               clock2 |= WM8904_SYSCLK_SRC;
+               rate = wm8904->fll_fout;
+               break;
+
+       default:
+               dev_err(codec->dev, "System clock not configured\n");
+               return -EINVAL;
+       }
+
+       /* SYSCLK shouldn't be over 13.5MHz */
+       if (rate > 13500000) {
+               clock0 = WM8904_MCLK_DIV;
+               wm8904->sysclk_rate = rate / 2;
+       } else {
+               clock0 = 0;
+               wm8904->sysclk_rate = rate;
+       }
+
+       snd_soc_update_bits(codec, WM8904_CLOCK_RATES_0, WM8904_MCLK_DIV,
+                           clock0);
+
+       snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2,
+                           WM8904_CLK_SYS_ENA | WM8904_SYSCLK_SRC, clock2);
+
+       dev_dbg(codec->dev, "CLK_SYS is %dHz\n", wm8904->sysclk_rate);
+
+       return 0;
+}
+
+static void wm8904_set_drc(struct snd_soc_codec *codec)
+{
+       struct wm8904_priv *wm8904 = codec->private_data;
+       struct wm8904_pdata *pdata = wm8904->pdata;
+       int save, i;
+
+       /* Save any enables; the configuration should clear them. */
+       save = snd_soc_read(codec, WM8904_DRC_0);
+
+       for (i = 0; i < WM8904_DRC_REGS; i++)
+               snd_soc_update_bits(codec, WM8904_DRC_0 + i, 0xffff,
+                                   pdata->drc_cfgs[wm8904->drc_cfg].regs[i]);
+
+       /* Reenable the DRC */
+       snd_soc_update_bits(codec, WM8904_DRC_0,
+                           WM8904_DRC_ENA | WM8904_DRC_DAC_PATH, save);
+}
+
+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 = codec->private_data;       
+       struct wm8904_pdata *pdata = wm8904->pdata;
+       int value = ucontrol->value.integer.value[0];
+
+       if (value >= pdata->num_drc_cfgs)
+               return -EINVAL;
+
+       wm8904->drc_cfg = value;
+
+       wm8904_set_drc(codec);
+
+       return 0;
+}
+
+static int wm8904_get_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 = codec->private_data;
+
+       ucontrol->value.enumerated.item[0] = wm8904->drc_cfg;
+
+       return 0;
+}
+
+static void wm8904_set_retune_mobile(struct snd_soc_codec *codec)
+{
+       struct wm8904_priv *wm8904 = codec->private_data;
+       struct wm8904_pdata *pdata = wm8904->pdata;
+       int best, best_val, save, i, cfg;
+
+       if (!pdata || !wm8904->num_retune_mobile_texts)
+               return;
+
+       /* Find the version of the currently selected configuration
+        * with the nearest sample rate. */
+       cfg = wm8904->retune_mobile_cfg;
+       best = 0;
+       best_val = INT_MAX;
+       for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) {
+               if (strcmp(pdata->retune_mobile_cfgs[i].name,
+                          wm8904->retune_mobile_texts[cfg]) == 0 &&
+                   abs(pdata->retune_mobile_cfgs[i].rate
+                       - wm8904->fs) < best_val) {
+                       best = i;
+                       best_val = abs(pdata->retune_mobile_cfgs[i].rate
+                                      - wm8904->fs);
+               }
+       }
+
+       dev_dbg(codec->dev, "ReTune Mobile %s/%dHz for %dHz sample rate\n",
+               pdata->retune_mobile_cfgs[best].name,
+               pdata->retune_mobile_cfgs[best].rate,
+               wm8904->fs);
+
+       /* The EQ will be disabled while reconfiguring it, remember the
+        * current configuration. 
+        */
+       save = snd_soc_read(codec, WM8904_EQ1);
+
+       for (i = 0; i < WM8904_EQ_REGS; i++)
+               snd_soc_update_bits(codec, WM8904_EQ1 + i, 0xffff,
+                               pdata->retune_mobile_cfgs[best].regs[i]);
+
+       snd_soc_update_bits(codec, WM8904_EQ1, WM8904_EQ_ENA, save);
+}
+
+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 = codec->private_data;       
+       struct wm8904_pdata *pdata = wm8904->pdata;
+       int value = ucontrol->value.integer.value[0];
+
+       if (value >= pdata->num_retune_mobile_cfgs)
+               return -EINVAL;
+
+       wm8904->retune_mobile_cfg = value;
+
+       wm8904_set_retune_mobile(codec);
+
+       return 0;
+}
+
+static int wm8904_get_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 = codec->private_data;
+
+       ucontrol->value.enumerated.item[0] = wm8904->retune_mobile_cfg;
+
+       return 0;
+}
+
+static int deemph_settings[] = { 0, 32000, 44100, 48000 };
+
+static int wm8904_set_deemph(struct snd_soc_codec *codec)
+{
+       struct wm8904_priv *wm8904 = codec->private_data;
+       int val, i, best;
+
+       /* If we're using deemphasis select the nearest available sample 
+        * rate.
+        */
+       if (wm8904->deemph) {
+               best = 1;
+               for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) {
+                       if (abs(deemph_settings[i] - wm8904->fs) <
+                           abs(deemph_settings[best] - wm8904->fs))
+                               best = i;
+               }
+
+               val = best << WM8904_DEEMPH_SHIFT;
+       } else {
+               val = 0;
+       }
+
+       dev_dbg(codec->dev, "Set deemphasis %d\n", val);
+
+       return snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_1,
+                                  WM8904_DEEMPH_MASK, val);
+}
+
+static int wm8904_get_deemph(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8904_priv *wm8904 = codec->private_data;
+
+       return wm8904->deemph;
+}
+
+static int wm8904_put_deemph(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8904_priv *wm8904 = codec->private_data;
+       int deemph = ucontrol->value.enumerated.item[0];
+
+       if (deemph > 1)
+               return -EINVAL;
+
+       wm8904->deemph = deemph;
+
+       return wm8904_set_deemph(codec);
+}
+
+static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
+static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 300, 0);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+
+static const char *input_mode_text[] = {
+       "Single-Ended", "Differential Line", "Differential Mic"
+};
+
+static const struct soc_enum lin_mode =
+       SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 0, 3, input_mode_text);
+
+static const struct soc_enum rin_mode =
+       SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 0, 3, input_mode_text);
+
+static const char *hpf_mode_text[] = {
+       "Hi-fi", "Voice 1", "Voice 2", "Voice 3"
+};
+
+static const struct soc_enum hpf_mode =
+       SOC_ENUM_SINGLE(WM8904_ADC_DIGITAL_0, 5, 4, hpf_mode_text);
+
+static const struct snd_kcontrol_new wm8904_adc_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8904_ADC_DIGITAL_VOLUME_LEFT,
+                WM8904_ADC_DIGITAL_VOLUME_RIGHT, 1, 119, 0, digital_tlv),
+
+SOC_ENUM("Left Caputure Mode", lin_mode),
+SOC_ENUM("Right Capture Mode", rin_mode),
+
+/* No TLV since it depends on mode */
+SOC_DOUBLE_R("Capture Volume", WM8904_ANALOGUE_LEFT_INPUT_0,
+            WM8904_ANALOGUE_RIGHT_INPUT_0, 0, 31, 0),
+SOC_DOUBLE_R("Capture Switch", WM8904_ANALOGUE_LEFT_INPUT_0,
+            WM8904_ANALOGUE_RIGHT_INPUT_0, 7, 1, 0),
+
+SOC_SINGLE("High Pass Filter Switch", WM8904_ADC_DIGITAL_0, 4, 1, 0),
+SOC_ENUM("High Pass Filter Mode", hpf_mode),
+
+SOC_SINGLE("ADC 128x OSR Switch", WM8904_ANALOGUE_ADC_0, 0, 1, 0),
+};
+
+static const char *drc_path_text[] = {
+       "ADC", "DAC"
+};
+
+static const struct soc_enum drc_path =
+       SOC_ENUM_SINGLE(WM8904_DRC_0, 14, 2, drc_path_text);
+
+static const struct snd_kcontrol_new wm8904_dac_snd_controls[] = {
+SOC_SINGLE_TLV("Digital Playback Boost Volume", 
+              WM8904_AUDIO_INTERFACE_0, 9, 3, 0, dac_boost_tlv),
+SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8904_DAC_DIGITAL_VOLUME_LEFT,
+                WM8904_DAC_DIGITAL_VOLUME_RIGHT, 1, 96, 0, digital_tlv),
+
+SOC_DOUBLE_R_TLV("Headphone Volume", WM8904_ANALOGUE_OUT1_LEFT,
+                WM8904_ANALOGUE_OUT1_RIGHT, 0, 63, 0, out_tlv),
+SOC_DOUBLE_R("Headphone Switch", WM8904_ANALOGUE_OUT1_LEFT,
+            WM8904_ANALOGUE_OUT1_RIGHT, 8, 1, 1),
+SOC_DOUBLE_R("Headphone ZC Switch", WM8904_ANALOGUE_OUT1_LEFT,
+            WM8904_ANALOGUE_OUT1_RIGHT, 6, 1, 0),
+
+SOC_DOUBLE_R_TLV("Line Output Volume", WM8904_ANALOGUE_OUT2_LEFT,
+                WM8904_ANALOGUE_OUT2_RIGHT, 0, 63, 0, out_tlv),
+SOC_DOUBLE_R("Line Output Switch", WM8904_ANALOGUE_OUT2_LEFT,
+            WM8904_ANALOGUE_OUT2_RIGHT, 8, 1, 1),
+SOC_DOUBLE_R("Line Output ZC Switch", WM8904_ANALOGUE_OUT2_LEFT,
+            WM8904_ANALOGUE_OUT2_RIGHT, 6, 1, 0),
+
+SOC_SINGLE("EQ Switch", WM8904_EQ1, 0, 1, 0),
+SOC_SINGLE("DRC Switch", WM8904_DRC_0, 15, 1, 0),
+SOC_ENUM("DRC Path", drc_path),
+SOC_SINGLE("DAC OSRx2 Switch", WM8904_DAC_DIGITAL_1, 6, 1, 0),
+SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0,
+                   wm8904_get_deemph, wm8904_put_deemph),
+};
+
+static const struct snd_kcontrol_new wm8904_snd_controls[] = {
+SOC_DOUBLE_TLV("Digital Sidetone Volume", WM8904_DAC_DIGITAL_0, 4, 8, 15, 0,
+              sidetone_tlv),
+};
+
+static const struct snd_kcontrol_new wm8904_eq_controls[] = {
+SOC_SINGLE_TLV("EQ1 Volume", WM8904_EQ2, 0, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 Volume", WM8904_EQ3, 0, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 Volume", WM8904_EQ4, 0, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 Volume", WM8904_EQ5, 0, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ5 Volume", WM8904_EQ6, 0, 24, 0, eq_tlv),
+};
+
+static int cp_event(struct snd_soc_dapm_widget *w,
+                   struct snd_kcontrol *kcontrol, int event)
+{
+       BUG_ON(event != SND_SOC_DAPM_POST_PMU);
+
+       /* Maximum startup time */
+       udelay(500);
+
+       return 0;
+}
+
+static int sysclk_event(struct snd_soc_dapm_widget *w,
+                        struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct wm8904_priv *wm8904 = codec->private_data;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               /* If we're using the FLL then we only start it when
+                * required; we assume that the configuration has been
+                * done previously and all we need to do is kick it
+                * off.
+                */
+               switch (wm8904->sysclk_src) {
+               case WM8904_CLK_FLL:
+                       snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
+                                           WM8904_FLL_OSC_ENA,
+                                           WM8904_FLL_OSC_ENA);
+
+                       snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
+                                           WM8904_FLL_ENA,
+                                           WM8904_FLL_ENA);
+                       break;
+
+               default:
+                       break;
+               }
+               break;
+
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
+                                   WM8904_FLL_OSC_ENA | WM8904_FLL_ENA, 0);
+               break;
+       }
+
+       return 0;
+}
+
+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 wm8904_priv *wm8904 = codec->private_data;
+       int reg, val;
+       int dcs_mask;
+       int dcs_l, dcs_r;
+       int dcs_l_reg, dcs_r_reg;
+       int timeout;
+       int pwr_reg;
+
+       /* This code is shared between HP and LINEOUT; we do all our
+        * power management in stereo pairs to avoid latency issues so
+        * we reuse shift to identify which rather than strcmp() the
+        * name. */
+       reg = w->shift;
+
+       switch (reg) {
+       case WM8904_ANALOGUE_HP_0:
+               pwr_reg = WM8904_POWER_MANAGEMENT_2;
+               dcs_mask = WM8904_DCS_ENA_CHAN_0 | WM8904_DCS_ENA_CHAN_1;
+               dcs_r_reg = WM8904_DC_SERVO_8;
+               dcs_l_reg = WM8904_DC_SERVO_9;
+               dcs_l = 0;
+               dcs_r = 1;
+               break;
+       case WM8904_ANALOGUE_LINEOUT_0:
+               pwr_reg = WM8904_POWER_MANAGEMENT_3;
+               dcs_mask = WM8904_DCS_ENA_CHAN_2 | WM8904_DCS_ENA_CHAN_3;
+               dcs_r_reg = WM8904_DC_SERVO_6;
+               dcs_l_reg = WM8904_DC_SERVO_7;
+               dcs_l = 2;
+               dcs_r = 3;
+               break;
+       default:
+               BUG();
+               return -EINVAL;
+       }
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               /* Power on the PGAs */
+               snd_soc_update_bits(codec, pwr_reg,
+                                   WM8904_HPL_PGA_ENA | WM8904_HPR_PGA_ENA,
+                                   WM8904_HPL_PGA_ENA | WM8904_HPR_PGA_ENA);
+
+               /* Power on the amplifier */
+               snd_soc_update_bits(codec, reg,
+                                   WM8904_HPL_ENA | WM8904_HPR_ENA,
+                                   WM8904_HPL_ENA | WM8904_HPR_ENA);
+
+
+               /* Enable the first stage */
+               snd_soc_update_bits(codec, reg,
+                                   WM8904_HPL_ENA_DLY | WM8904_HPR_ENA_DLY,
+                                   WM8904_HPL_ENA_DLY | WM8904_HPR_ENA_DLY);
+
+               /* Power up the DC servo */
+               snd_soc_update_bits(codec, WM8904_DC_SERVO_0,
+                                   dcs_mask, dcs_mask);
+
+               /* Either calibrate the DC servo or restore cached state
+                * if we have that.
+                */
+               if (wm8904->dcs_state[dcs_l] || wm8904->dcs_state[dcs_r]) {
+                       dev_dbg(codec->dev, "Restoring DC servo state\n");
+
+                       snd_soc_write(codec, dcs_l_reg,
+                                     wm8904->dcs_state[dcs_l]);
+                       snd_soc_write(codec, dcs_r_reg,
+                                     wm8904->dcs_state[dcs_r]);
+
+                       snd_soc_write(codec, WM8904_DC_SERVO_1, dcs_mask);
+
+                       timeout = 20;
+               } else {
+                       dev_dbg(codec->dev, "Calibrating DC servo\n");
+
+                       snd_soc_write(codec, WM8904_DC_SERVO_1,
+                               dcs_mask << WM8904_DCS_TRIG_STARTUP_0_SHIFT);
+
+                       timeout = 500;
+               }
+
+               /* Wait for DC servo to complete */
+               dcs_mask <<= WM8904_DCS_CAL_COMPLETE_SHIFT;
+               do {
+                       val = snd_soc_read(codec, WM8904_DC_SERVO_READBACK_0);
+                       if ((val & dcs_mask) == dcs_mask)
+                               break;
+
+                       msleep(1);
+               } while (--timeout);
+
+               if ((val & dcs_mask) != dcs_mask)
+                       dev_warn(codec->dev, "DC servo timed out\n");
+               else
+                       dev_dbg(codec->dev, "DC servo ready\n");
+
+               /* Enable the output stage */
+               snd_soc_update_bits(codec, reg,
+                                   WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP,
+                                   WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP);
+               break;
+
+       case SND_SOC_DAPM_POST_PMU:
+               /* Unshort the output itself */
+               snd_soc_update_bits(codec, reg,
+                                   WM8904_HPL_RMV_SHORT |
+                                   WM8904_HPR_RMV_SHORT,
+                                   WM8904_HPL_RMV_SHORT |
+                                   WM8904_HPR_RMV_SHORT);
+
+               break;
+
+       case SND_SOC_DAPM_PRE_PMD:
+               /* Short the output */
+               snd_soc_update_bits(codec, reg,
+                                   WM8904_HPL_RMV_SHORT |
+                                   WM8904_HPR_RMV_SHORT, 0);
+               break;
+
+       case SND_SOC_DAPM_POST_PMD:
+               /* Cache the DC servo configuration; this will be
+                * invalidated if we change the configuration. */
+               wm8904->dcs_state[dcs_l] = snd_soc_read(codec, dcs_l_reg);
+               wm8904->dcs_state[dcs_r] = snd_soc_read(codec, dcs_r_reg);
+
+               snd_soc_update_bits(codec, WM8904_DC_SERVO_0,
+                                   dcs_mask, 0);
+
+               /* Disable the amplifier input and output stages */
+               snd_soc_update_bits(codec, reg,
+                                   WM8904_HPL_ENA | WM8904_HPR_ENA |
+                                   WM8904_HPL_ENA_DLY | WM8904_HPR_ENA_DLY |
+                                   WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP,
+                                   0);
+
+               /* PGAs too */
+               snd_soc_update_bits(codec, pwr_reg,
+                                   WM8904_HPL_PGA_ENA | WM8904_HPR_PGA_ENA,
+                                   0);
+               break;
+       }
+
+       return 0;
+}
+
+static const char *lin_text[] = {
+       "IN1L", "IN2L", "IN3L"
+};
+
+static const struct soc_enum lin_enum =
+       SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 2, 3, lin_text);
+
+static const struct snd_kcontrol_new lin_mux =
+       SOC_DAPM_ENUM("Left Capture Mux", lin_enum);
+
+static const struct soc_enum lin_inv_enum =
+       SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 4, 3, lin_text);
+
+static const struct snd_kcontrol_new lin_inv_mux =
+       SOC_DAPM_ENUM("Left Capture Inveting Mux", lin_inv_enum);
+
+static const char *rin_text[] = {
+       "IN1R", "IN2R", "IN3R"
+};
+
+static const struct soc_enum rin_enum =
+       SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 2, 3, rin_text);
+
+static const struct snd_kcontrol_new rin_mux =
+       SOC_DAPM_ENUM("Right Capture Mux", rin_enum);
+
+static const struct soc_enum rin_inv_enum =
+       SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 4, 3, rin_text);
+
+static const struct snd_kcontrol_new rin_inv_mux =
+       SOC_DAPM_ENUM("Right Capture Inveting Mux", rin_inv_enum);
+
+static const char *aif_text[] = {
+       "Left", "Right"
+};
+
+static const struct soc_enum aifoutl_enum =
+       SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 7, 2, aif_text);
+
+static const struct snd_kcontrol_new aifoutl_mux =
+       SOC_DAPM_ENUM("AIFOUTL Mux", aifoutl_enum);
+
+static const struct soc_enum aifoutr_enum =
+       SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 6, 2, aif_text);
+
+static const struct snd_kcontrol_new aifoutr_mux =
+       SOC_DAPM_ENUM("AIFOUTR Mux", aifoutr_enum);
+
+static const struct soc_enum aifinl_enum =
+       SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 5, 2, aif_text);
+
+static const struct snd_kcontrol_new aifinl_mux =
+       SOC_DAPM_ENUM("AIFINL Mux", aifinl_enum);
+
+static const struct soc_enum aifinr_enum =
+       SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 4, 2, aif_text);
+
+static const struct snd_kcontrol_new aifinr_mux =
+       SOC_DAPM_ENUM("AIFINR Mux", aifinr_enum);
+
+static const struct snd_soc_dapm_widget wm8904_core_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("SYSCLK", WM8904_CLOCK_RATES_2, 2, 0, sysclk_event,
+                   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8904_CLOCK_RATES_2, 1, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("TOCLK", WM8904_CLOCK_RATES_2, 0, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8904_adc_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_MICBIAS("MICBIAS", WM8904_MIC_BIAS_CONTROL_0, 0, 0),
+
+SND_SOC_DAPM_MUX("Left Capture Mux", SND_SOC_NOPM, 0, 0, &lin_mux),
+SND_SOC_DAPM_MUX("Left Capture Inverting Mux", SND_SOC_NOPM, 0, 0,
+                &lin_inv_mux),
+SND_SOC_DAPM_MUX("Right Capture Mux", SND_SOC_NOPM, 0, 0, &rin_mux),
+SND_SOC_DAPM_MUX("Right Capture Inverting Mux", SND_SOC_NOPM, 0, 0,
+                &rin_inv_mux),
+
+SND_SOC_DAPM_PGA("Left Capture PGA", WM8904_POWER_MANAGEMENT_0, 1, 0,
+                NULL, 0),
+SND_SOC_DAPM_PGA("Right Capture PGA", WM8904_POWER_MANAGEMENT_0, 0, 0,
+                NULL, 0),
+
+SND_SOC_DAPM_ADC("ADCL", NULL, WM8904_POWER_MANAGEMENT_6, 1, 0),
+SND_SOC_DAPM_ADC("ADCR", NULL, WM8904_POWER_MANAGEMENT_6, 0, 0),
+
+SND_SOC_DAPM_MUX("AIFOUTL Mux", SND_SOC_NOPM, 0, 0, &aifoutl_mux),
+SND_SOC_DAPM_MUX("AIFOUTR Mux", SND_SOC_NOPM, 0, 0, &aifoutr_mux),
+
+SND_SOC_DAPM_AIF_OUT("AIFOUTL", "Capture", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_OUT("AIFOUTR", "Capture", 1, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8904_dac_dapm_widgets[] = {
+SND_SOC_DAPM_AIF_IN("AIFINL", "Playback", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_IN("AIFINR", "Playback", 1, SND_SOC_NOPM, 0, 0),
+
+SND_SOC_DAPM_MUX("DACL Mux", SND_SOC_NOPM, 0, 0, &aifinl_mux),
+SND_SOC_DAPM_MUX("DACR Mux", SND_SOC_NOPM, 0, 0, &aifinr_mux),
+
+SND_SOC_DAPM_DAC("DACL", NULL, WM8904_POWER_MANAGEMENT_6, 3, 0),
+SND_SOC_DAPM_DAC("DACR", NULL, WM8904_POWER_MANAGEMENT_6, 2, 0),
+
+SND_SOC_DAPM_SUPPLY("Charge pump", WM8904_CHARGE_PUMP_0, 0, 0, cp_event,
+                   SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_PGA("HPL PGA", SND_SOC_NOPM, 1, 0, NULL, 0),
+SND_SOC_DAPM_PGA("HPR PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("LINEL PGA", SND_SOC_NOPM, 1, 0, NULL, 0),
+SND_SOC_DAPM_PGA("LINER PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_E("Headphone Output", SND_SOC_NOPM, WM8904_ANALOGUE_HP_0,
+                  0, NULL, 0, out_pga_event,
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_PGA_E("Line Output", SND_SOC_NOPM, WM8904_ANALOGUE_LINEOUT_0,
+                  0, NULL, 0, out_pga_event,
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+SND_SOC_DAPM_OUTPUT("HPOUTL"),
+SND_SOC_DAPM_OUTPUT("HPOUTR"),
+SND_SOC_DAPM_OUTPUT("LINEOUTL"),
+SND_SOC_DAPM_OUTPUT("LINEOUTR"),
+};
+
+static const char *out_mux_text[] = {
+       "DAC", "Bypass"
+};
+
+static const struct soc_enum hpl_enum =
+       SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 3, 2, out_mux_text);
+
+static const struct snd_kcontrol_new hpl_mux =
+       SOC_DAPM_ENUM("HPL Mux", hpl_enum);
+
+static const struct soc_enum hpr_enum =
+       SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 2, 2, out_mux_text);
+
+static const struct snd_kcontrol_new hpr_mux =
+       SOC_DAPM_ENUM("HPR Mux", hpr_enum);
+
+static const struct soc_enum linel_enum =
+       SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 1, 2, out_mux_text);
+
+static const struct snd_kcontrol_new linel_mux =
+       SOC_DAPM_ENUM("LINEL Mux", linel_enum);
+
+static const struct soc_enum liner_enum =
+       SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 0, 2, out_mux_text);
+
+static const struct snd_kcontrol_new liner_mux =
+       SOC_DAPM_ENUM("LINEL Mux", liner_enum);
+
+static const char *sidetone_text[] = {
+       "None", "Left", "Right"
+};
+
+static const struct soc_enum dacl_sidetone_enum =
+       SOC_ENUM_SINGLE(WM8904_DAC_DIGITAL_0, 2, 3, sidetone_text);
+
+static const struct snd_kcontrol_new dacl_sidetone_mux =
+       SOC_DAPM_ENUM("Left Sidetone Mux", dacl_sidetone_enum);
+
+static const struct soc_enum dacr_sidetone_enum =
+       SOC_ENUM_SINGLE(WM8904_DAC_DIGITAL_0, 0, 3, sidetone_text);
+
+static const struct snd_kcontrol_new dacr_sidetone_mux =
+       SOC_DAPM_ENUM("Right Sidetone Mux", dacr_sidetone_enum);
+
+static const struct snd_soc_dapm_widget wm8904_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("Class G", WM8904_CLASS_W_0, 0, 1, NULL, 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_MUX("Left Sidetone", SND_SOC_NOPM, 0, 0, &dacl_sidetone_mux),
+SND_SOC_DAPM_MUX("Right Sidetone", SND_SOC_NOPM, 0, 0, &dacr_sidetone_mux),
+
+SND_SOC_DAPM_MUX("HPL Mux", SND_SOC_NOPM, 0, 0, &hpl_mux),
+SND_SOC_DAPM_MUX("HPR Mux", SND_SOC_NOPM, 0, 0, &hpr_mux),
+SND_SOC_DAPM_MUX("LINEL Mux", SND_SOC_NOPM, 0, 0, &linel_mux),
+SND_SOC_DAPM_MUX("LINER Mux", SND_SOC_NOPM, 0, 0, &liner_mux),
+};
+
+static const struct snd_soc_dapm_route core_intercon[] = {
+       { "CLK_DSP", NULL, "SYSCLK" },
+       { "TOCLK", NULL, "SYSCLK" },
+};
+
+static const struct snd_soc_dapm_route adc_intercon[] = {
+       { "Left Capture Mux", "IN1L", "IN1L" },
+       { "Left Capture Mux", "IN2L", "IN2L" },
+       { "Left Capture Mux", "IN3L", "IN3L" },
+
+       { "Left Capture Inverting Mux", "IN1L", "IN1L" },
+       { "Left Capture Inverting Mux", "IN2L", "IN2L" },
+       { "Left Capture Inverting Mux", "IN3L", "IN3L" },
+
+       { "Right Capture Mux", "IN1R", "IN1R" },
+       { "Right Capture Mux", "IN2R", "IN2R" },
+       { "Right Capture Mux", "IN3R", "IN3R" },
+
+       { "Right Capture Inverting Mux", "IN1R", "IN1R" },
+       { "Right Capture Inverting Mux", "IN2R", "IN2R" },
+       { "Right Capture Inverting Mux", "IN3R", "IN3R" },
+
+       { "Left Capture PGA", NULL, "Left Capture Mux" },
+       { "Left Capture PGA", NULL, "Left Capture Inverting Mux" },
+
+       { "Right Capture PGA", NULL, "Right Capture Mux" },
+       { "Right Capture PGA", NULL, "Right Capture Inverting Mux" },
+
+       { "AIFOUTL", "Left",  "ADCL" },
+       { "AIFOUTL", "Right", "ADCR" },
+       { "AIFOUTR", "Left",  "ADCL" },
+       { "AIFOUTR", "Right", "ADCR" },
+
+       { "ADCL", NULL, "CLK_DSP" },
+       { "ADCL", NULL, "Left Capture PGA" },
+
+       { "ADCR", NULL, "CLK_DSP" },
+       { "ADCR", NULL, "Right Capture PGA" },
+};
+
+static const struct snd_soc_dapm_route dac_intercon[] = {
+       { "DACL", "Right", "AIFINR" },
+       { "DACL", "Left",  "AIFINL" },
+       { "DACL", NULL, "CLK_DSP" },
+
+       { "DACR", "Right", "AIFINR" },
+       { "DACR", "Left",  "AIFINL" },
+       { "DACR", NULL, "CLK_DSP" },
+
+       { "Charge pump", NULL, "SYSCLK" },
+
+       { "Headphone Output", NULL, "HPL PGA" },
+       { "Headphone Output", NULL, "HPR PGA" },
+       { "Headphone Output", NULL, "Charge pump" },
+       { "Headphone Output", NULL, "TOCLK" },
+
+       { "Line Output", NULL, "LINEL PGA" },
+       { "Line Output", NULL, "LINER PGA" },
+       { "Line Output", NULL, "Charge pump" },
+       { "Line Output", NULL, "TOCLK" },
+
+       { "HPOUTL", NULL, "Headphone Output" },
+       { "HPOUTR", NULL, "Headphone Output" },
+
+       { "LINEOUTL", NULL, "Line Output" },
+       { "LINEOUTR", NULL, "Line Output" },
+};
+
+static const struct snd_soc_dapm_route wm8904_intercon[] = {
+       { "Left Sidetone", "Left", "ADCL" },
+       { "Left Sidetone", "Right", "ADCR" },
+       { "DACL", NULL, "Left Sidetone" },
+       
+       { "Right Sidetone", "Left", "ADCL" },
+       { "Right Sidetone", "Right", "ADCR" },
+       { "DACR", NULL, "Right Sidetone" },
+
+       { "Left Bypass", NULL, "Class G" },
+       { "Left Bypass", NULL, "Left Capture PGA" },
+
+       { "Right Bypass", NULL, "Class G" },
+       { "Right Bypass", NULL, "Right Capture PGA" },
+
+       { "HPL Mux", "DAC", "DACL" },
+       { "HPL Mux", "Bypass", "Left Bypass" },
+
+       { "HPR Mux", "DAC", "DACR" },
+       { "HPR Mux", "Bypass", "Right Bypass" },
+
+       { "LINEL Mux", "DAC", "DACL" },
+       { "LINEL Mux", "Bypass", "Left Bypass" },
+
+       { "LINER Mux", "DAC", "DACR" },
+       { "LINER Mux", "Bypass", "Right Bypass" },
+
+       { "HPL PGA", NULL, "HPL Mux" },
+       { "HPR PGA", NULL, "HPR Mux" },
+
+       { "LINEL PGA", NULL, "LINEL Mux" },
+       { "LINER PGA", NULL, "LINER Mux" },
+};
+
+static const struct snd_soc_dapm_route wm8912_intercon[] = {
+       { "HPL PGA", NULL, "DACL" },
+       { "HPR PGA", NULL, "DACR" },
+
+       { "LINEL PGA", NULL, "DACL" },
+       { "LINER PGA", NULL, "DACR" },
+};
+
+static int wm8904_add_widgets(struct snd_soc_codec *codec)
+{
+       struct wm8904_priv *wm8904 = codec->private_data;
+
+       snd_soc_dapm_new_controls(codec, wm8904_core_dapm_widgets,
+                                 ARRAY_SIZE(wm8904_core_dapm_widgets));
+       snd_soc_dapm_add_routes(codec, core_intercon,
+                               ARRAY_SIZE(core_intercon));
+
+       switch (wm8904->devtype) {
+       case WM8904:
+               snd_soc_add_controls(codec, wm8904_adc_snd_controls,
+                                    ARRAY_SIZE(wm8904_adc_snd_controls));
+               snd_soc_add_controls(codec, wm8904_dac_snd_controls,
+                                    ARRAY_SIZE(wm8904_dac_snd_controls));
+               snd_soc_add_controls(codec, wm8904_snd_controls,
+                                    ARRAY_SIZE(wm8904_snd_controls));
+
+               snd_soc_dapm_new_controls(codec, wm8904_adc_dapm_widgets,
+                                         ARRAY_SIZE(wm8904_adc_dapm_widgets));
+               snd_soc_dapm_new_controls(codec, wm8904_dac_dapm_widgets,
+                                         ARRAY_SIZE(wm8904_dac_dapm_widgets));
+               snd_soc_dapm_new_controls(codec, wm8904_dapm_widgets,
+                                         ARRAY_SIZE(wm8904_dapm_widgets));
+
+               snd_soc_dapm_add_routes(codec, core_intercon,
+                                       ARRAY_SIZE(core_intercon));
+               snd_soc_dapm_add_routes(codec, adc_intercon,
+                                       ARRAY_SIZE(adc_intercon));
+               snd_soc_dapm_add_routes(codec, dac_intercon,
+                                       ARRAY_SIZE(dac_intercon));
+               snd_soc_dapm_add_routes(codec, wm8904_intercon,
+                                       ARRAY_SIZE(wm8904_intercon));
+               break;
+
+       case WM8912:
+               snd_soc_add_controls(codec, wm8904_dac_snd_controls,
+                                    ARRAY_SIZE(wm8904_dac_snd_controls));
+
+               snd_soc_dapm_new_controls(codec, wm8904_dac_dapm_widgets,
+                                         ARRAY_SIZE(wm8904_dac_dapm_widgets));
+
+               snd_soc_dapm_add_routes(codec, dac_intercon,
+                                       ARRAY_SIZE(dac_intercon));
+               snd_soc_dapm_add_routes(codec, wm8912_intercon,
+                                       ARRAY_SIZE(wm8912_intercon));
+               break;
+       }
+
+       snd_soc_dapm_new_widgets(codec);
+       return 0;
+}
+
+static struct {
+       int ratio;
+       unsigned int clk_sys_rate;
+} clk_sys_rates[] = {
+       {   64,  0 },
+       {  128,  1 },
+       {  192,  2 },
+       {  256,  3 },
+       {  384,  4 },
+       {  512,  5 },
+       {  786,  6 },
+       { 1024,  7 },
+       { 1408,  8 },
+       { 1536,  9 },
+};
+
+static struct {
+       int rate;
+       int sample_rate;
+} sample_rates[] = {
+       { 8000,  0  },
+       { 11025, 1  },
+       { 12000, 1  },
+       { 16000, 2  },
+       { 22050, 3  },
+       { 24000, 3  },
+       { 32000, 4  },
+       { 44100, 5  },
+       { 48000, 5  },
+};
+
+static struct {
+       int div; /* *10 due to .5s */
+       int bclk_div;
+} bclk_divs[] = {
+       { 10,  0  },
+       { 15,  1  },
+       { 20,  2  },
+       { 30,  3  },
+       { 40,  4  },
+       { 50,  5  },
+       { 55,  6  },
+       { 60,  7  },
+       { 80,  8  },
+       { 100, 9  },
+       { 110, 10 },
+       { 120, 11 },
+       { 160, 12 },
+       { 200, 13 },
+       { 220, 14 },
+       { 240, 16 },
+       { 200, 17 },
+       { 320, 18 },
+       { 440, 19 },
+       { 480, 20 },
+};
+
+
+static int wm8904_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 wm8904_priv *wm8904 = codec->private_data;
+       int ret, i, best, best_val, cur_val;
+       unsigned int aif1 = 0;
+       unsigned int aif2 = 0;
+       unsigned int aif3 = 0;
+       unsigned int clock1 = 0;
+       unsigned int dac_digital1 = 0;
+
+       /* What BCLK do we need? */
+       wm8904->fs = params_rate(params);
+       if (wm8904->tdm_slots) {
+               dev_dbg(codec->dev, "Configuring for %d %d bit TDM slots\n",
+                       wm8904->tdm_slots, wm8904->tdm_width);
+               wm8904->bclk = snd_soc_calc_bclk(wm8904->fs,
+                                                wm8904->tdm_width, 2,
+                                                wm8904->tdm_slots);
+       } else {
+               wm8904->bclk = snd_soc_params_to_bclk(params);
+       }
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               aif1 |= 0x40;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               aif1 |= 0x80;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               aif1 |= 0xc0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+
+       dev_dbg(codec->dev, "Target BCLK is %dHz\n", wm8904->bclk);
+
+       ret = wm8904_configure_clocking(codec);
+       if (ret != 0)
+               return ret;
+
+       /* Select nearest CLK_SYS_RATE */
+       best = 0;
+       best_val = abs((wm8904->sysclk_rate / clk_sys_rates[0].ratio)
+                      - wm8904->fs);
+       for (i = 1; i < ARRAY_SIZE(clk_sys_rates); i++) {
+               cur_val = abs((wm8904->sysclk_rate /
+                              clk_sys_rates[i].ratio) - wm8904->fs);;
+               if (cur_val < best_val) {
+                       best = i;
+                       best_val = cur_val;
+               }
+       }
+       dev_dbg(codec->dev, "Selected CLK_SYS_RATIO of %d\n",
+               clk_sys_rates[best].ratio);
+       clock1 |= (clk_sys_rates[best].clk_sys_rate
+                  << WM8904_CLK_SYS_RATE_SHIFT);
+
+       /* SAMPLE_RATE */
+       best = 0;
+       best_val = abs(wm8904->fs - sample_rates[0].rate);
+       for (i = 1; i < ARRAY_SIZE(sample_rates); i++) {
+               /* Closest match */
+               cur_val = abs(wm8904->fs - sample_rates[i].rate);
+               if (cur_val < best_val) {
+                       best = i;
+                       best_val = cur_val;
+               }
+       }
+       dev_dbg(codec->dev, "Selected SAMPLE_RATE of %dHz\n",
+               sample_rates[best].rate);
+       clock1 |= (sample_rates[best].sample_rate
+                  << WM8904_SAMPLE_RATE_SHIFT);
+
+       /* Enable sloping stopband filter for low sample rates */
+       if (wm8904->fs <= 24000)
+               dac_digital1 |= WM8904_DAC_SB_FILT;
+
+       /* BCLK_DIV */
+       best = 0;
+       best_val = INT_MAX;
+       for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
+               cur_val = ((wm8904->sysclk_rate * 10) / bclk_divs[i].div)
+                       - wm8904->bclk;
+               if (cur_val < 0) /* Table is sorted */
+                       break;
+               if (cur_val < best_val) {
+                       best = i;
+                       best_val = cur_val;
+               }
+       }
+       wm8904->bclk = (wm8904->sysclk_rate * 10) / bclk_divs[best].div;
+       dev_dbg(codec->dev, "Selected BCLK_DIV of %d for %dHz BCLK\n",
+               bclk_divs[best].div, wm8904->bclk);
+       aif2 |= bclk_divs[best].bclk_div;
+
+       /* LRCLK is a simple fraction of BCLK */
+       dev_dbg(codec->dev, "LRCLK_RATE is %d\n", wm8904->bclk / wm8904->fs);
+       aif3 |= wm8904->bclk / wm8904->fs;
+
+       /* Apply the settings */
+       snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_1,
+                           WM8904_DAC_SB_FILT, dac_digital1);
+       snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_1,
+                           WM8904_AIF_WL_MASK, aif1);
+       snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_2,
+                           WM8904_BCLK_DIV_MASK, aif2);
+       snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_3,
+                           WM8904_LRCLK_RATE_MASK, aif3);
+       snd_soc_update_bits(codec, WM8904_CLOCK_RATES_1,
+                           WM8904_SAMPLE_RATE_MASK |
+                           WM8904_CLK_SYS_RATE_MASK, clock1);
+
+       /* Update filters for the new settings */
+       wm8904_set_retune_mobile(codec);
+       wm8904_set_deemph(codec);
+
+       return 0;
+}
+
+
+static int wm8904_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+                            unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct wm8904_priv *priv = codec->private_data;
+
+       switch (clk_id) {
+       case WM8904_CLK_MCLK:
+               priv->sysclk_src = clk_id;
+               priv->mclk_rate = freq;
+               break;
+
+       case WM8904_CLK_FLL:
+               priv->sysclk_src = clk_id;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       dev_dbg(dai->dev, "Clock source is %d at %uHz\n", clk_id, freq);
+
+       wm8904_configure_clocking(codec);
+
+       return 0;
+}
+
+static int wm8904_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       unsigned int aif1 = 0;
+       unsigned int aif3 = 0;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               break;
+       case SND_SOC_DAIFMT_CBS_CFM:
+               aif3 |= WM8904_LRCLK_DIR;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               aif1 |= WM8904_BCLK_DIR;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               aif1 |= WM8904_BCLK_DIR;
+               aif3 |= WM8904_LRCLK_DIR;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_B:
+               aif1 |= WM8904_AIF_LRCLK_INV;
+       case SND_SOC_DAIFMT_DSP_A:
+               aif1 |= 0x3;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               aif1 |= 0x2;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               aif1 |= 0x1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_A:
+       case SND_SOC_DAIFMT_DSP_B:
+               /* frame inversion not valid for DSP modes */
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       aif1 |= WM8904_AIF_BCLK_INV;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+
+       case SND_SOC_DAIFMT_I2S:
+       case SND_SOC_DAIFMT_RIGHT_J:
+       case SND_SOC_DAIFMT_LEFT_J:
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       break;
+               case SND_SOC_DAIFMT_IB_IF:
+                       aif1 |= WM8904_AIF_BCLK_INV | WM8904_AIF_LRCLK_INV;
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       aif1 |= WM8904_AIF_BCLK_INV;
+                       break;
+               case SND_SOC_DAIFMT_NB_IF:
+                       aif1 |= WM8904_AIF_LRCLK_INV;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_1,
+                           WM8904_AIF_BCLK_INV | WM8904_AIF_LRCLK_INV |
+                           WM8904_AIF_FMT_MASK | WM8904_BCLK_DIR, aif1);
+       snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_3,
+                           WM8904_LRCLK_DIR, aif3);
+
+       return 0;
+}
+
+
+static int wm8904_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+                              unsigned int rx_mask, int slots, int slot_width)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct wm8904_priv *wm8904 = codec->private_data;
+       int aif1 = 0;
+
+       /* Don't need to validate anything if we're turning off TDM */
+       if (slots == 0)
+               goto out;
+
+       /* Note that we allow configurations we can't handle ourselves - 
+        * for example, we can generate clocks for slots 2 and up even if
+        * we can't use those slots ourselves.
+        */
+       aif1 |= WM8904_AIFADC_TDM | WM8904_AIFDAC_TDM;
+
+       switch (rx_mask) {
+       case 3:
+               break;
+       case 0xc:
+               aif1 |= WM8904_AIFADC_TDM_CHAN;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+
+       switch (tx_mask) {
+       case 3:
+               break;
+       case 0xc:
+               aif1 |= WM8904_AIFDAC_TDM_CHAN;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+out:
+       wm8904->tdm_width = slot_width;
+       wm8904->tdm_slots = slots / 2;
+
+       snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_1,
+                           WM8904_AIFADC_TDM | WM8904_AIFADC_TDM_CHAN |
+                           WM8904_AIFDAC_TDM | WM8904_AIFDAC_TDM_CHAN, aif1);
+
+       return 0;
+}
+
+struct _fll_div {
+       u16 fll_fratio;
+       u16 fll_outdiv;
+       u16 fll_clk_ref_div;
+       u16 n;
+       u16 k;
+};
+
+/* 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)
+{
+       u64 Kpart;
+       unsigned int K, Ndiv, Nmod, target;
+       unsigned int div;
+       int i;
+
+       /* Fref must be <=13.5MHz */
+       div = 1;
+       fll_div->fll_clk_ref_div = 0;
+       while ((Fref / div) > 13500000) {
+               div *= 2;
+               fll_div->fll_clk_ref_div++;
+
+               if (div > 8) {
+                       pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
+                              Fref);
+                       return -EINVAL;
+               }
+       }
+
+       pr_debug("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 = 4;
+       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("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;
+                       target /= 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;
+       }
+
+       /* Now, calculate N.K */
+       Ndiv = target / Fref;
+
+       fll_div->n = Ndiv;
+       Nmod = target % Fref;
+       pr_debug("Nmod=%d\n", Nmod);
+
+       /* Calculate fractional part - scale up so we can round. */
+       Kpart = FIXED_FLL_SIZE * (long long)Nmod;
+
+       do_div(Kpart, Fref);
+
+       K = Kpart & 0xFFFFFFFF;
+
+       if ((K % 10) >= 5)
+               K += 5;
+
+       /* Move down to proper range now rounding is done */
+       fll_div->k = K / 10;
+
+       pr_debug("N=%x K=%x FLL_FRATIO=%x FLL_OUTDIV=%x FLL_CLK_REF_DIV=%x\n",
+                fll_div->n, fll_div->k,
+                fll_div->fll_fratio, fll_div->fll_outdiv,
+                fll_div->fll_clk_ref_div);
+
+       return 0;
+}
+
+static int wm8904_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 wm8904_priv *wm8904 = codec->private_data;
+       struct _fll_div fll_div;
+       int ret, val;
+       int clock2, fll1;
+
+       /* Any change? */
+       if (source == wm8904->fll_src && Fref == wm8904->fll_fref &&
+           Fout == wm8904->fll_fout)
+               return 0;
+
+       clock2 = snd_soc_read(codec, WM8904_CLOCK_RATES_2);
+
+       if (Fout == 0) {
+               dev_dbg(codec->dev, "FLL disabled\n");
+
+               wm8904->fll_fref = 0;
+               wm8904->fll_fout = 0;
+
+               /* Gate SYSCLK to avoid glitches */
+               snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2,
+                                   WM8904_CLK_SYS_ENA, 0);
+
+               snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
+                                   WM8904_FLL_OSC_ENA | WM8904_FLL_ENA, 0);
+
+               goto out;
+       }
+
+       /* Validate the FLL ID */
+       switch (source) {
+       case WM8904_FLL_MCLK:
+       case WM8904_FLL_LRCLK:
+       case WM8904_FLL_BCLK:
+               ret = fll_factors(&fll_div, Fref, Fout);
+               if (ret != 0)
+                       return ret;
+               break;
+
+       case WM8904_FLL_FREE_RUNNING:
+               dev_dbg(codec->dev, "Using free running FLL\n");
+               /* Force 12MHz and output/4 for now */
+               Fout = 12000000;
+               Fref = 12000000;
+
+               memset(&fll_div, 0, sizeof(fll_div));
+               fll_div.fll_outdiv = 3;
+               break;
+
+       default:
+               dev_err(codec->dev, "Unknown FLL ID %d\n", fll_id);
+               return -EINVAL;
+       }
+
+       /* Save current state then disable the FLL and SYSCLK to avoid
+        * misclocking */
+       fll1 = snd_soc_read(codec, WM8904_FLL_CONTROL_1);
+       snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2,
+                           WM8904_CLK_SYS_ENA, 0);
+       snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
+                           WM8904_FLL_OSC_ENA | WM8904_FLL_ENA, 0);
+
+       /* Unlock forced oscilator control to switch it on/off */
+       snd_soc_update_bits(codec, WM8904_CONTROL_INTERFACE_TEST_1,
+                           WM8904_USER_KEY, WM8904_USER_KEY);
+
+       if (fll_id == WM8904_FLL_FREE_RUNNING) {
+               val = WM8904_FLL_FRC_NCO;
+       } else {
+               val = 0;
+       }
+
+       snd_soc_update_bits(codec, WM8904_FLL_NCO_TEST_1, WM8904_FLL_FRC_NCO,
+                           val);
+       snd_soc_update_bits(codec, WM8904_CONTROL_INTERFACE_TEST_1,
+                           WM8904_USER_KEY, 0);
+
+       switch (fll_id) {
+       case WM8904_FLL_MCLK:
+               snd_soc_update_bits(codec, WM8904_FLL_CONTROL_5,
+                                   WM8904_FLL_CLK_REF_SRC_MASK, 0);
+               break;
+
+       case WM8904_FLL_LRCLK:
+               snd_soc_update_bits(codec, WM8904_FLL_CONTROL_5,
+                                   WM8904_FLL_CLK_REF_SRC_MASK, 1);
+               break;
+
+       case WM8904_FLL_BCLK:
+               snd_soc_update_bits(codec, WM8904_FLL_CONTROL_5,
+                                   WM8904_FLL_CLK_REF_SRC_MASK, 2);
+               break;
+       }
+
+       if (fll_div.k)
+               val = WM8904_FLL_FRACN_ENA;
+       else
+               val = 0;
+       snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
+                           WM8904_FLL_FRACN_ENA, val);
+
+       snd_soc_update_bits(codec, WM8904_FLL_CONTROL_2,
+                           WM8904_FLL_OUTDIV_MASK | WM8904_FLL_FRATIO_MASK,
+                           (fll_div.fll_outdiv << WM8904_FLL_OUTDIV_SHIFT) |
+                           (fll_div.fll_fratio << WM8904_FLL_FRATIO_SHIFT));
+
+       snd_soc_write(codec, WM8904_FLL_CONTROL_3, fll_div.k);
+
+       snd_soc_update_bits(codec, WM8904_FLL_CONTROL_4, WM8904_FLL_N_MASK,
+                           fll_div.n << WM8904_FLL_N_SHIFT);
+
+       snd_soc_update_bits(codec, WM8904_FLL_CONTROL_5,
+                           WM8904_FLL_CLK_REF_DIV_MASK,
+                           fll_div.fll_clk_ref_div 
+                           << WM8904_FLL_CLK_REF_DIV_SHIFT);
+
+       dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
+
+       wm8904->fll_fref = Fref;
+       wm8904->fll_fout = Fout;
+       wm8904->fll_src = source;
+
+       /* Enable the FLL if it was previously active */
+       snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
+                           WM8904_FLL_OSC_ENA, fll1);
+       snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
+                           WM8904_FLL_ENA, fll1);
+
+out:
+       /* Reenable SYSCLK if it was previously active */
+       snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2,
+                           WM8904_CLK_SYS_ENA, clock2);
+
+       return 0;
+}
+
+static int wm8904_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       int val;
+
+       if (mute)
+               val = WM8904_DAC_MUTE;
+       else
+               val = 0;
+
+       snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_1, WM8904_DAC_MUTE, val);
+
+       return 0;
+}
+
+static void wm8904_sync_cache(struct snd_soc_codec *codec)
+{
+       struct wm8904_priv *wm8904 = codec->private_data;
+       int i;
+
+       if (!codec->cache_sync)
+               return;
+
+       codec->cache_only = 0;
+
+       /* Sync back cached values if they're different from the
+        * hardware default.
+        */
+       for (i = 1; i < ARRAY_SIZE(wm8904->reg_cache); i++) {
+               if (!wm8904_access[i].writable)
+                       continue;
+
+               if (wm8904->reg_cache[i] == wm8904_reg[i])
+                       continue;
+
+               snd_soc_write(codec, i, wm8904->reg_cache[i]);
+       }
+
+       codec->cache_sync = 0;
+}
+
+static int wm8904_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       struct wm8904_priv *wm8904 = codec->private_data;
+       int ret;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+
+       case SND_SOC_BIAS_PREPARE:
+               /* VMID resistance 2*50k */
+               snd_soc_update_bits(codec, WM8904_VMID_CONTROL_0,
+                                   WM8904_VMID_RES_MASK,
+                                   0x1 << WM8904_VMID_RES_SHIFT);
+
+               /* Normal bias current */
+               snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0,
+                                   WM8904_ISEL_MASK, 2 << WM8904_ISEL_SHIFT);
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+                       ret = regulator_bulk_enable(ARRAY_SIZE(wm8904->supplies),
+                                                   wm8904->supplies);
+                       if (ret != 0) {
+                               dev_err(codec->dev,
+                                       "Failed to enable supplies: %d\n",
+                                       ret);
+                               return ret;
+                       }
+
+                       wm8904_sync_cache(codec);
+
+                       /* Enable bias */
+                       snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0,
+                                           WM8904_BIAS_ENA, WM8904_BIAS_ENA);
+
+                       /* Enable VMID, VMID buffering, 2*5k resistance */
+                       snd_soc_update_bits(codec, WM8904_VMID_CONTROL_0,
+                                           WM8904_VMID_ENA |
+                                           WM8904_VMID_RES_MASK,
+                                           WM8904_VMID_ENA |
+                                           0x3 << WM8904_VMID_RES_SHIFT);
+
+                       /* Let VMID ramp */
+                       msleep(1);
+               }
+
+               /* Maintain VMID with 2*250k */
+               snd_soc_update_bits(codec, WM8904_VMID_CONTROL_0,
+                                   WM8904_VMID_RES_MASK,
+                                   0x2 << WM8904_VMID_RES_SHIFT);
+
+               /* Bias current *0.5 */
+               snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0,
+                                   WM8904_ISEL_MASK, 0);
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               /* Turn off VMID */
+               snd_soc_update_bits(codec, WM8904_VMID_CONTROL_0,
+                                   WM8904_VMID_RES_MASK | WM8904_VMID_ENA, 0);
+
+               /* Stop bias generation */
+               snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0,
+                                   WM8904_BIAS_ENA, 0);
+
+#ifdef CONFIG_REGULATOR
+               /* Post 2.6.34 we will be able to get a callback when
+                * the regulators are disabled which we can use but
+                * for now just assume that the power will be cut if
+                * the regulator API is in use.
+                */
+               codec->cache_sync = 1;
+#endif
+
+               regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies),
+                                      wm8904->supplies);
+               break;
+       }
+       codec->bias_level = level;
+       return 0;
+}
+
+#define WM8904_RATES SNDRV_PCM_RATE_8000_96000
+
+#define WM8904_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 wm8904_dai_ops = {
+       .set_sysclk = wm8904_set_sysclk,
+       .set_fmt = wm8904_set_fmt,
+       .set_tdm_slot = wm8904_set_tdm_slot,
+       .set_pll = wm8904_set_fll,
+       .hw_params = wm8904_hw_params,
+       .digital_mute = wm8904_digital_mute,
+};
+
+struct snd_soc_dai wm8904_dai = {
+       .name = "WM8904",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = WM8904_RATES,
+               .formats = WM8904_FORMATS,
+       },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = WM8904_RATES,
+               .formats = WM8904_FORMATS,
+       },
+       .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)
+{
+       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)
+{
+       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;
+}
+#else
+#define wm8904_suspend NULL
+#define wm8904_resume NULL
+#endif
+
+static void wm8904_handle_retune_mobile_pdata(struct wm8904_priv *wm8904)
+{
+       struct snd_soc_codec *codec = &wm8904->codec;
+       struct wm8904_pdata *pdata = wm8904->pdata;
+       struct snd_kcontrol_new control =
+               SOC_ENUM_EXT("EQ Mode",
+                            wm8904->retune_mobile_enum,
+                            wm8904_get_retune_mobile_enum,
+                            wm8904_put_retune_mobile_enum);
+       int ret, i, j;
+       const char **t;
+
+       /* We need an array of texts for the enum API but the number
+        * of texts is likely to be less than the number of
+        * configurations due to the sample rate dependency of the
+        * configurations. */
+       wm8904->num_retune_mobile_texts = 0;
+       wm8904->retune_mobile_texts = NULL;
+       for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) {
+               for (j = 0; j < wm8904->num_retune_mobile_texts; j++) {
+                       if (strcmp(pdata->retune_mobile_cfgs[i].name,
+                                  wm8904->retune_mobile_texts[j]) == 0)
+                               break;
+               }
+
+               if (j != wm8904->num_retune_mobile_texts)
+                       continue;
+
+               /* Expand the array... */
+               t = krealloc(wm8904->retune_mobile_texts,
+                            sizeof(char *) * 
+                            (wm8904->num_retune_mobile_texts + 1),
+                            GFP_KERNEL);
+               if (t == NULL)
+                       continue;
+
+               /* ...store the new entry... */
+               t[wm8904->num_retune_mobile_texts] = 
+                       pdata->retune_mobile_cfgs[i].name;
+
+               /* ...and remember the new version. */
+               wm8904->num_retune_mobile_texts++;
+               wm8904->retune_mobile_texts = t;
+       }
+
+       dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n",
+               wm8904->num_retune_mobile_texts);
+
+       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);
+       if (ret != 0)
+               dev_err(wm8904->codec.dev,
+                       "Failed to add ReTune Mobile control: %d\n", ret);
+}
+
+static void wm8904_handle_pdata(struct wm8904_priv *wm8904)
+{
+       struct snd_soc_codec *codec = &wm8904->codec;
+       struct wm8904_pdata *pdata = wm8904->pdata;
+       int ret, i;
+
+       if (!pdata) {
+               snd_soc_add_controls(&wm8904->codec, wm8904_eq_controls,
+                                    ARRAY_SIZE(wm8904_eq_controls));
+               return;
+       }
+
+       dev_dbg(codec->dev, "%d DRC configurations\n", pdata->num_drc_cfgs);
+
+       if (pdata->num_drc_cfgs) {
+               struct snd_kcontrol_new control =
+                       SOC_ENUM_EXT("DRC Mode", wm8904->drc_enum,
+                                    wm8904_get_drc_enum, wm8904_put_drc_enum);
+
+               /* We need an array of texts for the enum API */
+               wm8904->drc_texts = kmalloc(sizeof(char *)
+                                           * pdata->num_drc_cfgs, GFP_KERNEL);
+               if (!wm8904->drc_texts) {
+                       dev_err(wm8904->codec.dev,
+                               "Failed to allocate %d DRC config texts\n",
+                               pdata->num_drc_cfgs);
+                       return;
+               }
+
+               for (i = 0; i < pdata->num_drc_cfgs; i++)
+                       wm8904->drc_texts[i] = pdata->drc_cfgs[i].name;
+
+               wm8904->drc_enum.max = pdata->num_drc_cfgs;
+               wm8904->drc_enum.texts = wm8904->drc_texts;
+
+               ret = snd_soc_add_controls(&wm8904->codec, &control, 1);
+               if (ret != 0)
+                       dev_err(wm8904->codec.dev,
+                               "Failed to add DRC mode control: %d\n", ret);
+
+               wm8904_set_drc(codec);
+       }
+
+       dev_dbg(codec->dev, "%d ReTune Mobile configurations\n",
+               pdata->num_retune_mobile_cfgs);
+
+       if (pdata->num_retune_mobile_cfgs)
+               wm8904_handle_retune_mobile_pdata(wm8904);
+       else
+               snd_soc_add_controls(&wm8904->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(codec->private_data);
+
+       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)
+{
+       int ret;
+       struct snd_soc_codec *codec = &wm8904->codec;
+       int i;
+
+       if (wm8904_codec) {
+               dev_err(codec->dev, "Another WM8904 is registered\n");
+               return -EINVAL;
+       }
+
+       mutex_init(&codec->mutex);
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+
+       codec->private_data = 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;
+
+       switch (wm8904->devtype) {
+       case WM8904:
+               break;
+       case WM8912:
+               memset(&wm8904_dai.capture, 0, sizeof(wm8904_dai.capture));
+               break;
+       default:
+               dev_err(codec->dev, "Unknown device type %d\n",
+                       wm8904->devtype);
+               return -EINVAL;
+       }
+
+       memcpy(codec->reg_cache, wm8904_reg, sizeof(wm8904_reg));
+
+       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;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(wm8904->supplies); i++)
+               wm8904->supplies[i].supply = wm8904_supply_names[i];
+
+       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8904->supplies),
+                                wm8904->supplies);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+               goto err;
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(wm8904->supplies),
+                                   wm8904->supplies);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+               goto err_get;
+       }
+
+       ret = snd_soc_read(codec, WM8904_SW_RESET_AND_ID);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to read ID register\n");
+               goto err_enable;
+       }
+       if (ret != wm8904_reg[WM8904_SW_RESET_AND_ID]) {
+               dev_err(codec->dev, "Device is not a WM8904, ID is %x\n", ret);
+               ret = -EINVAL;
+               goto err_enable;
+       }
+
+       ret = snd_soc_read(codec, WM8904_REVISION);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to read device revision: %d\n",
+                       ret);
+               goto err_enable;
+       }
+       dev_info(codec->dev, "revision %c\n", ret + 'A');
+
+       ret = wm8904_reset(codec);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to issue reset\n");
+               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;
+       wm8904->reg_cache[WM8904_DAC_DIGITAL_VOLUME_LEFT] |= WM8904_DAC_VU;
+       wm8904->reg_cache[WM8904_DAC_DIGITAL_VOLUME_RIGHT] |= WM8904_DAC_VU;
+       wm8904->reg_cache[WM8904_ANALOGUE_OUT1_LEFT] |= WM8904_HPOUT_VU |
+               WM8904_HPOUTLZC;
+       wm8904->reg_cache[WM8904_ANALOGUE_OUT1_RIGHT] |= WM8904_HPOUT_VU |
+               WM8904_HPOUTRZC;
+       wm8904->reg_cache[WM8904_ANALOGUE_OUT2_LEFT] |= WM8904_LINEOUT_VU |
+               WM8904_LINEOUTLZC;
+       wm8904->reg_cache[WM8904_ANALOGUE_OUT2_RIGHT] |= WM8904_LINEOUT_VU |
+               WM8904_LINEOUTRZC;
+       wm8904->reg_cache[WM8904_CLOCK_RATES_0] &= ~WM8904_SR_MODE;
+
+       /* Set Class W by default - this will be managed by the Class
+        * G widget at runtime where bypass paths are available.
+        */
+       wm8904->reg_cache[WM8904_CLASS_W_0] |= WM8904_CP_DYN_PWR;
+
+       /* Use normal bias source */
+       wm8904->reg_cache[WM8904_BIAS_CONTROL_0] &= ~WM8904_POBCTRL;
+
+       wm8904_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       /* Bias level configuration will have done an extra enable */
+       regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
+
+       wm8904_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(&wm8904_dai);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
+               snd_soc_unregister_codec(codec);
+               return ret;
+       }
+
+       return 0;
+
+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)
+{
+       wm8904_set_bias_level(&wm8904->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;
+}
+
+#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;
+
+       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->pdata = i2c->dev.platform_data;
+
+       codec->dev = &i2c->dev;
+
+       return wm8904_register(wm8904, SND_SOC_I2C);
+}
+
+static __devexit int wm8904_i2c_remove(struct i2c_client *client)
+{
+       struct wm8904_priv *wm8904 = i2c_get_clientdata(client);
+       wm8904_unregister(wm8904);
+       return 0;
+}
+
+static const struct i2c_device_id wm8904_i2c_id[] = {
+       { "wm8904", WM8904 },
+       { "wm8912", WM8912 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8904_i2c_id);
+
+static struct i2c_driver wm8904_i2c_driver = {
+       .driver = {
+               .name = "WM8904",
+               .owner = THIS_MODULE,
+       },
+       .probe =    wm8904_i2c_probe,
+       .remove =   __devexit_p(wm8904_i2c_remove),
+       .id_table = wm8904_i2c_id,
+};
+#endif
+
+static int __init wm8904_modinit(void)
+{
+       int ret;
+#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",
+                      ret);
+       }
+#endif
+       return 0;
+}
+module_init(wm8904_modinit);
+
+static void __exit wm8904_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&wm8904_i2c_driver);
+#endif
+}
+module_exit(wm8904_exit);
+
+MODULE_DESCRIPTION("ASoC WM8904 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8904.h b/sound/soc/codecs/wm8904.h
new file mode 100644 (file)
index 0000000..b68886d
--- /dev/null
@@ -0,0 +1,1681 @@
+/*
+ * wm8904.h  --  WM8904 ASoC driver
+ *
+ * Copyright 2009 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 _WM8904_H
+#define _WM8904_H
+
+#define WM8904_CLK_MCLK 1
+#define WM8904_CLK_FLL  2
+
+#define WM8904_FLL_MCLK          1
+#define WM8904_FLL_BCLK          2
+#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.
+ */
+#define WM8904_SW_RESET_AND_ID                  0x00
+#define WM8904_REVISION                                0x01
+#define WM8904_BIAS_CONTROL_0                   0x04
+#define WM8904_VMID_CONTROL_0                   0x05
+#define WM8904_MIC_BIAS_CONTROL_0               0x06
+#define WM8904_MIC_BIAS_CONTROL_1               0x07
+#define WM8904_ANALOGUE_DAC_0                   0x08
+#define WM8904_MIC_FILTER_CONTROL               0x09
+#define WM8904_ANALOGUE_ADC_0                   0x0A
+#define WM8904_POWER_MANAGEMENT_0               0x0C
+#define WM8904_POWER_MANAGEMENT_2               0x0E
+#define WM8904_POWER_MANAGEMENT_3               0x0F
+#define WM8904_POWER_MANAGEMENT_6               0x12
+#define WM8904_CLOCK_RATES_0                    0x14
+#define WM8904_CLOCK_RATES_1                    0x15
+#define WM8904_CLOCK_RATES_2                    0x16
+#define WM8904_AUDIO_INTERFACE_0                0x18
+#define WM8904_AUDIO_INTERFACE_1                0x19
+#define WM8904_AUDIO_INTERFACE_2                0x1A
+#define WM8904_AUDIO_INTERFACE_3                0x1B
+#define WM8904_DAC_DIGITAL_VOLUME_LEFT          0x1E
+#define WM8904_DAC_DIGITAL_VOLUME_RIGHT         0x1F
+#define WM8904_DAC_DIGITAL_0                    0x20
+#define WM8904_DAC_DIGITAL_1                    0x21
+#define WM8904_ADC_DIGITAL_VOLUME_LEFT          0x24
+#define WM8904_ADC_DIGITAL_VOLUME_RIGHT         0x25
+#define WM8904_ADC_DIGITAL_0                    0x26
+#define WM8904_DIGITAL_MICROPHONE_0             0x27
+#define WM8904_DRC_0                            0x28
+#define WM8904_DRC_1                            0x29
+#define WM8904_DRC_2                            0x2A
+#define WM8904_DRC_3                            0x2B
+#define WM8904_ANALOGUE_LEFT_INPUT_0            0x2C
+#define WM8904_ANALOGUE_RIGHT_INPUT_0           0x2D
+#define WM8904_ANALOGUE_LEFT_INPUT_1            0x2E
+#define WM8904_ANALOGUE_RIGHT_INPUT_1           0x2F
+#define WM8904_ANALOGUE_OUT1_LEFT               0x39
+#define WM8904_ANALOGUE_OUT1_RIGHT              0x3A
+#define WM8904_ANALOGUE_OUT2_LEFT               0x3B
+#define WM8904_ANALOGUE_OUT2_RIGHT              0x3C
+#define WM8904_ANALOGUE_OUT12_ZC                0x3D
+#define WM8904_DC_SERVO_0                       0x43
+#define WM8904_DC_SERVO_1                       0x44
+#define WM8904_DC_SERVO_2                       0x45
+#define WM8904_DC_SERVO_4                       0x47
+#define WM8904_DC_SERVO_5                       0x48
+#define WM8904_DC_SERVO_6                       0x49
+#define WM8904_DC_SERVO_7                       0x4A
+#define WM8904_DC_SERVO_8                       0x4B
+#define WM8904_DC_SERVO_9                       0x4C
+#define WM8904_DC_SERVO_READBACK_0              0x4D
+#define WM8904_ANALOGUE_HP_0                    0x5A
+#define WM8904_ANALOGUE_LINEOUT_0               0x5E
+#define WM8904_CHARGE_PUMP_0                    0x62
+#define WM8904_CLASS_W_0                        0x68
+#define WM8904_WRITE_SEQUENCER_0                0x6C
+#define WM8904_WRITE_SEQUENCER_1                0x6D
+#define WM8904_WRITE_SEQUENCER_2                0x6E
+#define WM8904_WRITE_SEQUENCER_3                0x6F
+#define WM8904_WRITE_SEQUENCER_4                0x70
+#define WM8904_FLL_CONTROL_1                    0x74
+#define WM8904_FLL_CONTROL_2                    0x75
+#define WM8904_FLL_CONTROL_3                    0x76
+#define WM8904_FLL_CONTROL_4                    0x77
+#define WM8904_FLL_CONTROL_5                    0x78
+#define WM8904_GPIO_CONTROL_1                   0x79
+#define WM8904_GPIO_CONTROL_2                   0x7A
+#define WM8904_GPIO_CONTROL_3                   0x7B
+#define WM8904_GPIO_CONTROL_4                   0x7C
+#define WM8904_DIGITAL_PULLS                    0x7E
+#define WM8904_INTERRUPT_STATUS                 0x7F
+#define WM8904_INTERRUPT_STATUS_MASK            0x80
+#define WM8904_INTERRUPT_POLARITY               0x81
+#define WM8904_INTERRUPT_DEBOUNCE               0x82
+#define WM8904_EQ1                              0x86
+#define WM8904_EQ2                              0x87
+#define WM8904_EQ3                              0x88
+#define WM8904_EQ4                              0x89
+#define WM8904_EQ5                              0x8A
+#define WM8904_EQ6                              0x8B
+#define WM8904_EQ7                              0x8C
+#define WM8904_EQ8                              0x8D
+#define WM8904_EQ9                              0x8E
+#define WM8904_EQ10                             0x8F
+#define WM8904_EQ11                             0x90
+#define WM8904_EQ12                             0x91
+#define WM8904_EQ13                             0x92
+#define WM8904_EQ14                             0x93
+#define WM8904_EQ15                             0x94
+#define WM8904_EQ16                             0x95
+#define WM8904_EQ17                             0x96
+#define WM8904_EQ18                             0x97
+#define WM8904_EQ19                             0x98
+#define WM8904_EQ20                             0x99
+#define WM8904_EQ21                             0x9A
+#define WM8904_EQ22                             0x9B
+#define WM8904_EQ23                             0x9C
+#define WM8904_EQ24                             0x9D
+#define WM8904_CONTROL_INTERFACE_TEST_1         0xA1
+#define WM8904_ANALOGUE_OUTPUT_BIAS_0           0xCC
+#define WM8904_FLL_NCO_TEST_0                   0xF7
+#define WM8904_FLL_NCO_TEST_1                   0xF8
+
+#define WM8904_REGISTER_COUNT                   101
+#define WM8904_MAX_REGISTER                     0xF8
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - SW Reset and ID
+ */
+#define WM8904_SW_RST_DEV_ID1_MASK              0xFFFF  /* SW_RST_DEV_ID1 - [15:0] */
+#define WM8904_SW_RST_DEV_ID1_SHIFT                  0  /* SW_RST_DEV_ID1 - [15:0] */
+#define WM8904_SW_RST_DEV_ID1_WIDTH                 16  /* SW_RST_DEV_ID1 - [15:0] */
+
+/*
+ * R1 (0x01) - Revision
+ */
+#define WM8904_REVISION_MASK                   0x000F  /* REVISION - [3:0] */
+#define WM8904_REVISION_SHIFT                       0  /* REVISION - [3:0] */
+#define WM8904_REVISION_WIDTH                      16  /* REVISION - [3:0] */
+
+/*
+ * R4 (0x04) - Bias Control 0
+ */
+#define WM8904_POBCTRL                          0x0010  /* POBCTRL */
+#define WM8904_POBCTRL_MASK                     0x0010  /* POBCTRL */
+#define WM8904_POBCTRL_SHIFT                         4  /* POBCTRL */
+#define WM8904_POBCTRL_WIDTH                         1  /* POBCTRL */
+#define WM8904_ISEL_MASK                        0x000C  /* ISEL - [3:2] */
+#define WM8904_ISEL_SHIFT                            2  /* ISEL - [3:2] */
+#define WM8904_ISEL_WIDTH                            2  /* ISEL - [3:2] */
+#define WM8904_STARTUP_BIAS_ENA                 0x0002  /* STARTUP_BIAS_ENA */
+#define WM8904_STARTUP_BIAS_ENA_MASK            0x0002  /* STARTUP_BIAS_ENA */
+#define WM8904_STARTUP_BIAS_ENA_SHIFT                1  /* STARTUP_BIAS_ENA */
+#define WM8904_STARTUP_BIAS_ENA_WIDTH                1  /* STARTUP_BIAS_ENA */
+#define WM8904_BIAS_ENA                         0x0001  /* BIAS_ENA */
+#define WM8904_BIAS_ENA_MASK                    0x0001  /* BIAS_ENA */
+#define WM8904_BIAS_ENA_SHIFT                        0  /* BIAS_ENA */
+#define WM8904_BIAS_ENA_WIDTH                        1  /* BIAS_ENA */
+
+/*
+ * R5 (0x05) - VMID Control 0
+ */
+#define WM8904_VMID_BUF_ENA                     0x0040  /* VMID_BUF_ENA */
+#define WM8904_VMID_BUF_ENA_MASK                0x0040  /* VMID_BUF_ENA */
+#define WM8904_VMID_BUF_ENA_SHIFT                    6  /* VMID_BUF_ENA */
+#define WM8904_VMID_BUF_ENA_WIDTH                    1  /* VMID_BUF_ENA */
+#define WM8904_VMID_RES_MASK                    0x0006  /* VMID_RES - [2:1] */
+#define WM8904_VMID_RES_SHIFT                        1  /* VMID_RES - [2:1] */
+#define WM8904_VMID_RES_WIDTH                        2  /* VMID_RES - [2:1] */
+#define WM8904_VMID_ENA                         0x0001  /* VMID_ENA */
+#define WM8904_VMID_ENA_MASK                    0x0001  /* VMID_ENA */
+#define WM8904_VMID_ENA_SHIFT                        0  /* VMID_ENA */
+#define WM8904_VMID_ENA_WIDTH                        1  /* VMID_ENA */
+
+/*
+ * R6 (0x06) - Mic Bias Control 0
+ */
+#define WM8904_MICDET_THR_MASK                  0x0070  /* MICDET_THR - [6:4] */
+#define WM8904_MICDET_THR_SHIFT                      4  /* MICDET_THR - [6:4] */
+#define WM8904_MICDET_THR_WIDTH                      3  /* MICDET_THR - [6:4] */
+#define WM8904_MICSHORT_THR_MASK                0x000C  /* MICSHORT_THR - [3:2] */
+#define WM8904_MICSHORT_THR_SHIFT                    2  /* MICSHORT_THR - [3:2] */
+#define WM8904_MICSHORT_THR_WIDTH                    2  /* MICSHORT_THR - [3:2] */
+#define WM8904_MICDET_ENA                       0x0002  /* MICDET_ENA */
+#define WM8904_MICDET_ENA_MASK                  0x0002  /* MICDET_ENA */
+#define WM8904_MICDET_ENA_SHIFT                      1  /* MICDET_ENA */
+#define WM8904_MICDET_ENA_WIDTH                      1  /* MICDET_ENA */
+#define WM8904_MICBIAS_ENA                      0x0001  /* MICBIAS_ENA */
+#define WM8904_MICBIAS_ENA_MASK                 0x0001  /* MICBIAS_ENA */
+#define WM8904_MICBIAS_ENA_SHIFT                     0  /* MICBIAS_ENA */
+#define WM8904_MICBIAS_ENA_WIDTH                     1  /* MICBIAS_ENA */
+
+/*
+ * R7 (0x07) - Mic Bias Control 1
+ */
+#define WM8904_MIC_DET_FILTER_ENA               0x8000  /* MIC_DET_FILTER_ENA */
+#define WM8904_MIC_DET_FILTER_ENA_MASK          0x8000  /* MIC_DET_FILTER_ENA */
+#define WM8904_MIC_DET_FILTER_ENA_SHIFT             15  /* MIC_DET_FILTER_ENA */
+#define WM8904_MIC_DET_FILTER_ENA_WIDTH              1  /* MIC_DET_FILTER_ENA */
+#define WM8904_MIC_SHORT_FILTER_ENA             0x4000  /* MIC_SHORT_FILTER_ENA */
+#define WM8904_MIC_SHORT_FILTER_ENA_MASK        0x4000  /* MIC_SHORT_FILTER_ENA */
+#define WM8904_MIC_SHORT_FILTER_ENA_SHIFT           14  /* MIC_SHORT_FILTER_ENA */
+#define WM8904_MIC_SHORT_FILTER_ENA_WIDTH            1  /* MIC_SHORT_FILTER_ENA */
+#define WM8904_MICBIAS_SEL_MASK                 0x0007  /* MICBIAS_SEL - [2:0] */
+#define WM8904_MICBIAS_SEL_SHIFT                     0  /* MICBIAS_SEL - [2:0] */
+#define WM8904_MICBIAS_SEL_WIDTH                     3  /* MICBIAS_SEL - [2:0] */
+
+/*
+ * R8 (0x08) - Analogue DAC 0
+ */
+#define WM8904_DAC_BIAS_SEL_MASK                0x0018  /* DAC_BIAS_SEL - [4:3] */
+#define WM8904_DAC_BIAS_SEL_SHIFT                    3  /* DAC_BIAS_SEL - [4:3] */
+#define WM8904_DAC_BIAS_SEL_WIDTH                    2  /* DAC_BIAS_SEL - [4:3] */
+#define WM8904_DAC_VMID_BIAS_SEL_MASK           0x0006  /* DAC_VMID_BIAS_SEL - [2:1] */
+#define WM8904_DAC_VMID_BIAS_SEL_SHIFT               1  /* DAC_VMID_BIAS_SEL - [2:1] */
+#define WM8904_DAC_VMID_BIAS_SEL_WIDTH               2  /* DAC_VMID_BIAS_SEL - [2:1] */
+
+/*
+ * R9 (0x09) - mic Filter Control
+ */
+#define WM8904_MIC_DET_SET_THRESHOLD_MASK       0xF000  /* MIC_DET_SET_THRESHOLD - [15:12] */
+#define WM8904_MIC_DET_SET_THRESHOLD_SHIFT          12  /* MIC_DET_SET_THRESHOLD - [15:12] */
+#define WM8904_MIC_DET_SET_THRESHOLD_WIDTH           4  /* MIC_DET_SET_THRESHOLD - [15:12] */
+#define WM8904_MIC_DET_RESET_THRESHOLD_MASK     0x0F00  /* MIC_DET_RESET_THRESHOLD - [11:8] */
+#define WM8904_MIC_DET_RESET_THRESHOLD_SHIFT         8  /* MIC_DET_RESET_THRESHOLD - [11:8] */
+#define WM8904_MIC_DET_RESET_THRESHOLD_WIDTH         4  /* MIC_DET_RESET_THRESHOLD - [11:8] */
+#define WM8904_MIC_SHORT_SET_THRESHOLD_MASK     0x00F0  /* MIC_SHORT_SET_THRESHOLD - [7:4] */
+#define WM8904_MIC_SHORT_SET_THRESHOLD_SHIFT         4  /* MIC_SHORT_SET_THRESHOLD - [7:4] */
+#define WM8904_MIC_SHORT_SET_THRESHOLD_WIDTH         4  /* MIC_SHORT_SET_THRESHOLD - [7:4] */
+#define WM8904_MIC_SHORT_RESET_THRESHOLD_MASK   0x000F  /* MIC_SHORT_RESET_THRESHOLD - [3:0] */
+#define WM8904_MIC_SHORT_RESET_THRESHOLD_SHIFT       0  /* MIC_SHORT_RESET_THRESHOLD - [3:0] */
+#define WM8904_MIC_SHORT_RESET_THRESHOLD_WIDTH       4  /* MIC_SHORT_RESET_THRESHOLD - [3:0] */
+
+/*
+ * R10 (0x0A) - Analogue ADC 0
+ */
+#define WM8904_ADC_OSR128                       0x0001  /* ADC_OSR128 */
+#define WM8904_ADC_OSR128_MASK                  0x0001  /* ADC_OSR128 */
+#define WM8904_ADC_OSR128_SHIFT                      0  /* ADC_OSR128 */
+#define WM8904_ADC_OSR128_WIDTH                      1  /* ADC_OSR128 */
+
+/*
+ * R12 (0x0C) - Power Management 0
+ */
+#define WM8904_INL_ENA                          0x0002  /* INL_ENA */
+#define WM8904_INL_ENA_MASK                     0x0002  /* INL_ENA */
+#define WM8904_INL_ENA_SHIFT                         1  /* INL_ENA */
+#define WM8904_INL_ENA_WIDTH                         1  /* INL_ENA */
+#define WM8904_INR_ENA                          0x0001  /* INR_ENA */
+#define WM8904_INR_ENA_MASK                     0x0001  /* INR_ENA */
+#define WM8904_INR_ENA_SHIFT                         0  /* INR_ENA */
+#define WM8904_INR_ENA_WIDTH                         1  /* INR_ENA */
+
+/*
+ * R14 (0x0E) - Power Management 2
+ */
+#define WM8904_HPL_PGA_ENA                      0x0002  /* HPL_PGA_ENA */
+#define WM8904_HPL_PGA_ENA_MASK                 0x0002  /* HPL_PGA_ENA */
+#define WM8904_HPL_PGA_ENA_SHIFT                     1  /* HPL_PGA_ENA */
+#define WM8904_HPL_PGA_ENA_WIDTH                     1  /* HPL_PGA_ENA */
+#define WM8904_HPR_PGA_ENA                      0x0001  /* HPR_PGA_ENA */
+#define WM8904_HPR_PGA_ENA_MASK                 0x0001  /* HPR_PGA_ENA */
+#define WM8904_HPR_PGA_ENA_SHIFT                     0  /* HPR_PGA_ENA */
+#define WM8904_HPR_PGA_ENA_WIDTH                     1  /* HPR_PGA_ENA */
+
+/*
+ * R15 (0x0F) - Power Management 3
+ */
+#define WM8904_LINEOUTL_PGA_ENA                 0x0002  /* LINEOUTL_PGA_ENA */
+#define WM8904_LINEOUTL_PGA_ENA_MASK            0x0002  /* LINEOUTL_PGA_ENA */
+#define WM8904_LINEOUTL_PGA_ENA_SHIFT                1  /* LINEOUTL_PGA_ENA */
+#define WM8904_LINEOUTL_PGA_ENA_WIDTH                1  /* LINEOUTL_PGA_ENA */
+#define WM8904_LINEOUTR_PGA_ENA                 0x0001  /* LINEOUTR_PGA_ENA */
+#define WM8904_LINEOUTR_PGA_ENA_MASK            0x0001  /* LINEOUTR_PGA_ENA */
+#define WM8904_LINEOUTR_PGA_ENA_SHIFT                0  /* LINEOUTR_PGA_ENA */
+#define WM8904_LINEOUTR_PGA_ENA_WIDTH                1  /* LINEOUTR_PGA_ENA */
+
+/*
+ * R18 (0x12) - Power Management 6
+ */
+#define WM8904_DACL_ENA                         0x0008  /* DACL_ENA */
+#define WM8904_DACL_ENA_MASK                    0x0008  /* DACL_ENA */
+#define WM8904_DACL_ENA_SHIFT                        3  /* DACL_ENA */
+#define WM8904_DACL_ENA_WIDTH                        1  /* DACL_ENA */
+#define WM8904_DACR_ENA                         0x0004  /* DACR_ENA */
+#define WM8904_DACR_ENA_MASK                    0x0004  /* DACR_ENA */
+#define WM8904_DACR_ENA_SHIFT                        2  /* DACR_ENA */
+#define WM8904_DACR_ENA_WIDTH                        1  /* DACR_ENA */
+#define WM8904_ADCL_ENA                         0x0002  /* ADCL_ENA */
+#define WM8904_ADCL_ENA_MASK                    0x0002  /* ADCL_ENA */
+#define WM8904_ADCL_ENA_SHIFT                        1  /* ADCL_ENA */
+#define WM8904_ADCL_ENA_WIDTH                        1  /* ADCL_ENA */
+#define WM8904_ADCR_ENA                         0x0001  /* ADCR_ENA */
+#define WM8904_ADCR_ENA_MASK                    0x0001  /* ADCR_ENA */
+#define WM8904_ADCR_ENA_SHIFT                        0  /* ADCR_ENA */
+#define WM8904_ADCR_ENA_WIDTH                        1  /* ADCR_ENA */
+
+/*
+ * R20 (0x14) - Clock Rates 0
+ */
+#define WM8904_TOCLK_RATE_DIV16                 0x4000  /* TOCLK_RATE_DIV16 */
+#define WM8904_TOCLK_RATE_DIV16_MASK            0x4000  /* TOCLK_RATE_DIV16 */
+#define WM8904_TOCLK_RATE_DIV16_SHIFT               14  /* TOCLK_RATE_DIV16 */
+#define WM8904_TOCLK_RATE_DIV16_WIDTH                1  /* TOCLK_RATE_DIV16 */
+#define WM8904_TOCLK_RATE_X4                    0x2000  /* TOCLK_RATE_X4 */
+#define WM8904_TOCLK_RATE_X4_MASK               0x2000  /* TOCLK_RATE_X4 */
+#define WM8904_TOCLK_RATE_X4_SHIFT                  13  /* TOCLK_RATE_X4 */
+#define WM8904_TOCLK_RATE_X4_WIDTH                   1  /* TOCLK_RATE_X4 */
+#define WM8904_SR_MODE                          0x1000  /* SR_MODE */
+#define WM8904_SR_MODE_MASK                     0x1000  /* SR_MODE */
+#define WM8904_SR_MODE_SHIFT                        12  /* SR_MODE */
+#define WM8904_SR_MODE_WIDTH                         1  /* SR_MODE */
+#define WM8904_MCLK_DIV                         0x0001  /* MCLK_DIV */
+#define WM8904_MCLK_DIV_MASK                    0x0001  /* MCLK_DIV */
+#define WM8904_MCLK_DIV_SHIFT                        0  /* MCLK_DIV */
+#define WM8904_MCLK_DIV_WIDTH                        1  /* MCLK_DIV */
+
+/*
+ * R21 (0x15) - Clock Rates 1
+ */
+#define WM8904_CLK_SYS_RATE_MASK                0x3C00  /* CLK_SYS_RATE - [13:10] */
+#define WM8904_CLK_SYS_RATE_SHIFT                   10  /* CLK_SYS_RATE - [13:10] */
+#define WM8904_CLK_SYS_RATE_WIDTH                    4  /* CLK_SYS_RATE - [13:10] */
+#define WM8904_SAMPLE_RATE_MASK                 0x0007  /* SAMPLE_RATE - [2:0] */
+#define WM8904_SAMPLE_RATE_SHIFT                     0  /* SAMPLE_RATE - [2:0] */
+#define WM8904_SAMPLE_RATE_WIDTH                     3  /* SAMPLE_RATE - [2:0] */
+
+/*
+ * R22 (0x16) - Clock Rates 2
+ */
+#define WM8904_MCLK_INV                         0x8000  /* MCLK_INV */
+#define WM8904_MCLK_INV_MASK                    0x8000  /* MCLK_INV */
+#define WM8904_MCLK_INV_SHIFT                       15  /* MCLK_INV */
+#define WM8904_MCLK_INV_WIDTH                        1  /* MCLK_INV */
+#define WM8904_SYSCLK_SRC                       0x4000  /* SYSCLK_SRC */
+#define WM8904_SYSCLK_SRC_MASK                  0x4000  /* SYSCLK_SRC */
+#define WM8904_SYSCLK_SRC_SHIFT                     14  /* SYSCLK_SRC */
+#define WM8904_SYSCLK_SRC_WIDTH                      1  /* SYSCLK_SRC */
+#define WM8904_TOCLK_RATE                       0x1000  /* TOCLK_RATE */
+#define WM8904_TOCLK_RATE_MASK                  0x1000  /* TOCLK_RATE */
+#define WM8904_TOCLK_RATE_SHIFT                     12  /* TOCLK_RATE */
+#define WM8904_TOCLK_RATE_WIDTH                      1  /* TOCLK_RATE */
+#define WM8904_OPCLK_ENA                        0x0008  /* OPCLK_ENA */
+#define WM8904_OPCLK_ENA_MASK                   0x0008  /* OPCLK_ENA */
+#define WM8904_OPCLK_ENA_SHIFT                       3  /* OPCLK_ENA */
+#define WM8904_OPCLK_ENA_WIDTH                       1  /* OPCLK_ENA */
+#define WM8904_CLK_SYS_ENA                      0x0004  /* CLK_SYS_ENA */
+#define WM8904_CLK_SYS_ENA_MASK                 0x0004  /* CLK_SYS_ENA */
+#define WM8904_CLK_SYS_ENA_SHIFT                     2  /* CLK_SYS_ENA */
+#define WM8904_CLK_SYS_ENA_WIDTH                     1  /* CLK_SYS_ENA */
+#define WM8904_CLK_DSP_ENA                      0x0002  /* CLK_DSP_ENA */
+#define WM8904_CLK_DSP_ENA_MASK                 0x0002  /* CLK_DSP_ENA */
+#define WM8904_CLK_DSP_ENA_SHIFT                     1  /* CLK_DSP_ENA */
+#define WM8904_CLK_DSP_ENA_WIDTH                     1  /* CLK_DSP_ENA */
+#define WM8904_TOCLK_ENA                        0x0001  /* TOCLK_ENA */
+#define WM8904_TOCLK_ENA_MASK                   0x0001  /* TOCLK_ENA */
+#define WM8904_TOCLK_ENA_SHIFT                       0  /* TOCLK_ENA */
+#define WM8904_TOCLK_ENA_WIDTH                       1  /* TOCLK_ENA */
+
+/*
+ * R24 (0x18) - Audio Interface 0
+ */
+#define WM8904_DACL_DATINV                      0x1000  /* DACL_DATINV */
+#define WM8904_DACL_DATINV_MASK                 0x1000  /* DACL_DATINV */
+#define WM8904_DACL_DATINV_SHIFT                    12  /* DACL_DATINV */
+#define WM8904_DACL_DATINV_WIDTH                     1  /* DACL_DATINV */
+#define WM8904_DACR_DATINV                      0x0800  /* DACR_DATINV */
+#define WM8904_DACR_DATINV_MASK                 0x0800  /* DACR_DATINV */
+#define WM8904_DACR_DATINV_SHIFT                    11  /* DACR_DATINV */
+#define WM8904_DACR_DATINV_WIDTH                     1  /* DACR_DATINV */
+#define WM8904_DAC_BOOST_MASK                   0x0600  /* DAC_BOOST - [10:9] */
+#define WM8904_DAC_BOOST_SHIFT                       9  /* DAC_BOOST - [10:9] */
+#define WM8904_DAC_BOOST_WIDTH                       2  /* DAC_BOOST - [10:9] */
+#define WM8904_LOOPBACK                         0x0100  /* LOOPBACK */
+#define WM8904_LOOPBACK_MASK                    0x0100  /* LOOPBACK */
+#define WM8904_LOOPBACK_SHIFT                        8  /* LOOPBACK */
+#define WM8904_LOOPBACK_WIDTH                        1  /* LOOPBACK */
+#define WM8904_AIFADCL_SRC                      0x0080  /* AIFADCL_SRC */
+#define WM8904_AIFADCL_SRC_MASK                 0x0080  /* AIFADCL_SRC */
+#define WM8904_AIFADCL_SRC_SHIFT                     7  /* AIFADCL_SRC */
+#define WM8904_AIFADCL_SRC_WIDTH                     1  /* AIFADCL_SRC */
+#define WM8904_AIFADCR_SRC                      0x0040  /* AIFADCR_SRC */
+#define WM8904_AIFADCR_SRC_MASK                 0x0040  /* AIFADCR_SRC */
+#define WM8904_AIFADCR_SRC_SHIFT                     6  /* AIFADCR_SRC */
+#define WM8904_AIFADCR_SRC_WIDTH                     1  /* AIFADCR_SRC */
+#define WM8904_AIFDACL_SRC                      0x0020  /* AIFDACL_SRC */
+#define WM8904_AIFDACL_SRC_MASK                 0x0020  /* AIFDACL_SRC */
+#define WM8904_AIFDACL_SRC_SHIFT                     5  /* AIFDACL_SRC */
+#define WM8904_AIFDACL_SRC_WIDTH                     1  /* AIFDACL_SRC */
+#define WM8904_AIFDACR_SRC                      0x0010  /* AIFDACR_SRC */
+#define WM8904_AIFDACR_SRC_MASK                 0x0010  /* AIFDACR_SRC */
+#define WM8904_AIFDACR_SRC_SHIFT                     4  /* AIFDACR_SRC */
+#define WM8904_AIFDACR_SRC_WIDTH                     1  /* AIFDACR_SRC */
+#define WM8904_ADC_COMP                         0x0008  /* ADC_COMP */
+#define WM8904_ADC_COMP_MASK                    0x0008  /* ADC_COMP */
+#define WM8904_ADC_COMP_SHIFT                        3  /* ADC_COMP */
+#define WM8904_ADC_COMP_WIDTH                        1  /* ADC_COMP */
+#define WM8904_ADC_COMPMODE                     0x0004  /* ADC_COMPMODE */
+#define WM8904_ADC_COMPMODE_MASK                0x0004  /* ADC_COMPMODE */
+#define WM8904_ADC_COMPMODE_SHIFT                    2  /* ADC_COMPMODE */
+#define WM8904_ADC_COMPMODE_WIDTH                    1  /* ADC_COMPMODE */
+#define WM8904_DAC_COMP                         0x0002  /* DAC_COMP */
+#define WM8904_DAC_COMP_MASK                    0x0002  /* DAC_COMP */
+#define WM8904_DAC_COMP_SHIFT                        1  /* DAC_COMP */
+#define WM8904_DAC_COMP_WIDTH                        1  /* DAC_COMP */
+#define WM8904_DAC_COMPMODE                     0x0001  /* DAC_COMPMODE */
+#define WM8904_DAC_COMPMODE_MASK                0x0001  /* DAC_COMPMODE */
+#define WM8904_DAC_COMPMODE_SHIFT                    0  /* DAC_COMPMODE */
+#define WM8904_DAC_COMPMODE_WIDTH                    1  /* DAC_COMPMODE */
+
+/*
+ * R25 (0x19) - Audio Interface 1
+ */
+#define WM8904_AIFDAC_TDM                       0x2000  /* AIFDAC_TDM */
+#define WM8904_AIFDAC_TDM_MASK                  0x2000  /* AIFDAC_TDM */
+#define WM8904_AIFDAC_TDM_SHIFT                     13  /* AIFDAC_TDM */
+#define WM8904_AIFDAC_TDM_WIDTH                      1  /* AIFDAC_TDM */
+#define WM8904_AIFDAC_TDM_CHAN                  0x1000  /* AIFDAC_TDM_CHAN */
+#define WM8904_AIFDAC_TDM_CHAN_MASK             0x1000  /* AIFDAC_TDM_CHAN */
+#define WM8904_AIFDAC_TDM_CHAN_SHIFT                12  /* AIFDAC_TDM_CHAN */
+#define WM8904_AIFDAC_TDM_CHAN_WIDTH                 1  /* AIFDAC_TDM_CHAN */
+#define WM8904_AIFADC_TDM                       0x0800  /* AIFADC_TDM */
+#define WM8904_AIFADC_TDM_MASK                  0x0800  /* AIFADC_TDM */
+#define WM8904_AIFADC_TDM_SHIFT                     11  /* AIFADC_TDM */
+#define WM8904_AIFADC_TDM_WIDTH                      1  /* AIFADC_TDM */
+#define WM8904_AIFADC_TDM_CHAN                  0x0400  /* AIFADC_TDM_CHAN */
+#define WM8904_AIFADC_TDM_CHAN_MASK             0x0400  /* AIFADC_TDM_CHAN */
+#define WM8904_AIFADC_TDM_CHAN_SHIFT                10  /* AIFADC_TDM_CHAN */
+#define WM8904_AIFADC_TDM_CHAN_WIDTH                 1  /* AIFADC_TDM_CHAN */
+#define WM8904_AIF_TRIS                         0x0100  /* AIF_TRIS */
+#define WM8904_AIF_TRIS_MASK                    0x0100  /* AIF_TRIS */
+#define WM8904_AIF_TRIS_SHIFT                        8  /* AIF_TRIS */
+#define WM8904_AIF_TRIS_WIDTH                        1  /* AIF_TRIS */
+#define WM8904_AIF_BCLK_INV                     0x0080  /* AIF_BCLK_INV */
+#define WM8904_AIF_BCLK_INV_MASK                0x0080  /* AIF_BCLK_INV */
+#define WM8904_AIF_BCLK_INV_SHIFT                    7  /* AIF_BCLK_INV */
+#define WM8904_AIF_BCLK_INV_WIDTH                    1  /* AIF_BCLK_INV */
+#define WM8904_BCLK_DIR                         0x0040  /* BCLK_DIR */
+#define WM8904_BCLK_DIR_MASK                    0x0040  /* BCLK_DIR */
+#define WM8904_BCLK_DIR_SHIFT                        6  /* BCLK_DIR */
+#define WM8904_BCLK_DIR_WIDTH                        1  /* BCLK_DIR */
+#define WM8904_AIF_LRCLK_INV                    0x0010  /* AIF_LRCLK_INV */
+#define WM8904_AIF_LRCLK_INV_MASK               0x0010  /* AIF_LRCLK_INV */
+#define WM8904_AIF_LRCLK_INV_SHIFT                   4  /* AIF_LRCLK_INV */
+#define WM8904_AIF_LRCLK_INV_WIDTH                   1  /* AIF_LRCLK_INV */
+#define WM8904_AIF_WL_MASK                      0x000C  /* AIF_WL - [3:2] */
+#define WM8904_AIF_WL_SHIFT                          2  /* AIF_WL - [3:2] */
+#define WM8904_AIF_WL_WIDTH                          2  /* AIF_WL - [3:2] */
+#define WM8904_AIF_FMT_MASK                     0x0003  /* AIF_FMT - [1:0] */
+#define WM8904_AIF_FMT_SHIFT                         0  /* AIF_FMT - [1:0] */
+#define WM8904_AIF_FMT_WIDTH                         2  /* AIF_FMT - [1:0] */
+
+/*
+ * R26 (0x1A) - Audio Interface 2
+ */
+#define WM8904_OPCLK_DIV_MASK                   0x0F00  /* OPCLK_DIV - [11:8] */
+#define WM8904_OPCLK_DIV_SHIFT                       8  /* OPCLK_DIV - [11:8] */
+#define WM8904_OPCLK_DIV_WIDTH                       4  /* OPCLK_DIV - [11:8] */
+#define WM8904_BCLK_DIV_MASK                    0x001F  /* BCLK_DIV - [4:0] */
+#define WM8904_BCLK_DIV_SHIFT                        0  /* BCLK_DIV - [4:0] */
+#define WM8904_BCLK_DIV_WIDTH                        5  /* BCLK_DIV - [4:0] */
+
+/*
+ * R27 (0x1B) - Audio Interface 3
+ */
+#define WM8904_LRCLK_DIR                        0x0800  /* LRCLK_DIR */
+#define WM8904_LRCLK_DIR_MASK                   0x0800  /* LRCLK_DIR */
+#define WM8904_LRCLK_DIR_SHIFT                      11  /* LRCLK_DIR */
+#define WM8904_LRCLK_DIR_WIDTH                       1  /* LRCLK_DIR */
+#define WM8904_LRCLK_RATE_MASK                  0x07FF  /* LRCLK_RATE - [10:0] */
+#define WM8904_LRCLK_RATE_SHIFT                      0  /* LRCLK_RATE - [10:0] */
+#define WM8904_LRCLK_RATE_WIDTH                     11  /* LRCLK_RATE - [10:0] */
+
+/*
+ * R30 (0x1E) - DAC Digital Volume Left
+ */
+#define WM8904_DAC_VU                           0x0100  /* DAC_VU */
+#define WM8904_DAC_VU_MASK                      0x0100  /* DAC_VU */
+#define WM8904_DAC_VU_SHIFT                          8  /* DAC_VU */
+#define WM8904_DAC_VU_WIDTH                          1  /* DAC_VU */
+#define WM8904_DACL_VOL_MASK                    0x00FF  /* DACL_VOL - [7:0] */
+#define WM8904_DACL_VOL_SHIFT                        0  /* DACL_VOL - [7:0] */
+#define WM8904_DACL_VOL_WIDTH                        8  /* DACL_VOL - [7:0] */
+
+/*
+ * R31 (0x1F) - DAC Digital Volume Right
+ */
+#define WM8904_DAC_VU                           0x0100  /* DAC_VU */
+#define WM8904_DAC_VU_MASK                      0x0100  /* DAC_VU */
+#define WM8904_DAC_VU_SHIFT                          8  /* DAC_VU */
+#define WM8904_DAC_VU_WIDTH                          1  /* DAC_VU */
+#define WM8904_DACR_VOL_MASK                    0x00FF  /* DACR_VOL - [7:0] */
+#define WM8904_DACR_VOL_SHIFT                        0  /* DACR_VOL - [7:0] */
+#define WM8904_DACR_VOL_WIDTH                        8  /* DACR_VOL - [7:0] */
+
+/*
+ * R32 (0x20) - DAC Digital 0
+ */
+#define WM8904_ADCL_DAC_SVOL_MASK               0x0F00  /* ADCL_DAC_SVOL - [11:8] */
+#define WM8904_ADCL_DAC_SVOL_SHIFT                   8  /* ADCL_DAC_SVOL - [11:8] */
+#define WM8904_ADCL_DAC_SVOL_WIDTH                   4  /* ADCL_DAC_SVOL - [11:8] */
+#define WM8904_ADCR_DAC_SVOL_MASK               0x00F0  /* ADCR_DAC_SVOL - [7:4] */
+#define WM8904_ADCR_DAC_SVOL_SHIFT                   4  /* ADCR_DAC_SVOL - [7:4] */
+#define WM8904_ADCR_DAC_SVOL_WIDTH                   4  /* ADCR_DAC_SVOL - [7:4] */
+#define WM8904_ADC_TO_DACL_MASK                 0x000C  /* ADC_TO_DACL - [3:2] */
+#define WM8904_ADC_TO_DACL_SHIFT                     2  /* ADC_TO_DACL - [3:2] */
+#define WM8904_ADC_TO_DACL_WIDTH                     2  /* ADC_TO_DACL - [3:2] */
+#define WM8904_ADC_TO_DACR_MASK                 0x0003  /* ADC_TO_DACR - [1:0] */
+#define WM8904_ADC_TO_DACR_SHIFT                     0  /* ADC_TO_DACR - [1:0] */
+#define WM8904_ADC_TO_DACR_WIDTH                     2  /* ADC_TO_DACR - [1:0] */
+
+/*
+ * R33 (0x21) - DAC Digital 1
+ */
+#define WM8904_DAC_MONO                         0x1000  /* DAC_MONO */
+#define WM8904_DAC_MONO_MASK                    0x1000  /* DAC_MONO */
+#define WM8904_DAC_MONO_SHIFT                       12  /* DAC_MONO */
+#define WM8904_DAC_MONO_WIDTH                        1  /* DAC_MONO */
+#define WM8904_DAC_SB_FILT                      0x0800  /* DAC_SB_FILT */
+#define WM8904_DAC_SB_FILT_MASK                 0x0800  /* DAC_SB_FILT */
+#define WM8904_DAC_SB_FILT_SHIFT                    11  /* DAC_SB_FILT */
+#define WM8904_DAC_SB_FILT_WIDTH                     1  /* DAC_SB_FILT */
+#define WM8904_DAC_MUTERATE                     0x0400  /* DAC_MUTERATE */
+#define WM8904_DAC_MUTERATE_MASK                0x0400  /* DAC_MUTERATE */
+#define WM8904_DAC_MUTERATE_SHIFT                   10  /* DAC_MUTERATE */
+#define WM8904_DAC_MUTERATE_WIDTH                    1  /* DAC_MUTERATE */
+#define WM8904_DAC_UNMUTE_RAMP                  0x0200  /* DAC_UNMUTE_RAMP */
+#define WM8904_DAC_UNMUTE_RAMP_MASK             0x0200  /* DAC_UNMUTE_RAMP */
+#define WM8904_DAC_UNMUTE_RAMP_SHIFT                 9  /* DAC_UNMUTE_RAMP */
+#define WM8904_DAC_UNMUTE_RAMP_WIDTH                 1  /* DAC_UNMUTE_RAMP */
+#define WM8904_DAC_OSR128                       0x0040  /* DAC_OSR128 */
+#define WM8904_DAC_OSR128_MASK                  0x0040  /* DAC_OSR128 */
+#define WM8904_DAC_OSR128_SHIFT                      6  /* DAC_OSR128 */
+#define WM8904_DAC_OSR128_WIDTH                      1  /* DAC_OSR128 */
+#define WM8904_DAC_MUTE                         0x0008  /* DAC_MUTE */
+#define WM8904_DAC_MUTE_MASK                    0x0008  /* DAC_MUTE */
+#define WM8904_DAC_MUTE_SHIFT                        3  /* DAC_MUTE */
+#define WM8904_DAC_MUTE_WIDTH                        1  /* DAC_MUTE */
+#define WM8904_DEEMPH_MASK                      0x0006  /* DEEMPH - [2:1] */
+#define WM8904_DEEMPH_SHIFT                          1  /* DEEMPH - [2:1] */
+#define WM8904_DEEMPH_WIDTH                          2  /* DEEMPH - [2:1] */
+
+/*
+ * R36 (0x24) - ADC Digital Volume Left
+ */
+#define WM8904_ADC_VU                           0x0100  /* ADC_VU */
+#define WM8904_ADC_VU_MASK                      0x0100  /* ADC_VU */
+#define WM8904_ADC_VU_SHIFT                          8  /* ADC_VU */
+#define WM8904_ADC_VU_WIDTH                          1  /* ADC_VU */
+#define WM8904_ADCL_VOL_MASK                    0x00FF  /* ADCL_VOL - [7:0] */
+#define WM8904_ADCL_VOL_SHIFT                        0  /* ADCL_VOL - [7:0] */
+#define WM8904_ADCL_VOL_WIDTH                        8  /* ADCL_VOL - [7:0] */
+
+/*
+ * R37 (0x25) - ADC Digital Volume Right
+ */
+#define WM8904_ADC_VU                           0x0100  /* ADC_VU */
+#define WM8904_ADC_VU_MASK                      0x0100  /* ADC_VU */
+#define WM8904_ADC_VU_SHIFT                          8  /* ADC_VU */
+#define WM8904_ADC_VU_WIDTH                          1  /* ADC_VU */
+#define WM8904_ADCR_VOL_MASK                    0x00FF  /* ADCR_VOL - [7:0] */
+#define WM8904_ADCR_VOL_SHIFT                        0  /* ADCR_VOL - [7:0] */
+#define WM8904_ADCR_VOL_WIDTH                        8  /* ADCR_VOL - [7:0] */
+
+/*
+ * R38 (0x26) - ADC Digital 0
+ */
+#define WM8904_ADC_HPF_CUT_MASK                 0x0060  /* ADC_HPF_CUT - [6:5] */
+#define WM8904_ADC_HPF_CUT_SHIFT                     5  /* ADC_HPF_CUT - [6:5] */
+#define WM8904_ADC_HPF_CUT_WIDTH                     2  /* ADC_HPF_CUT - [6:5] */
+#define WM8904_ADC_HPF                          0x0010  /* ADC_HPF */
+#define WM8904_ADC_HPF_MASK                     0x0010  /* ADC_HPF */
+#define WM8904_ADC_HPF_SHIFT                         4  /* ADC_HPF */
+#define WM8904_ADC_HPF_WIDTH                         1  /* ADC_HPF */
+#define WM8904_ADCL_DATINV                      0x0002  /* ADCL_DATINV */
+#define WM8904_ADCL_DATINV_MASK                 0x0002  /* ADCL_DATINV */
+#define WM8904_ADCL_DATINV_SHIFT                     1  /* ADCL_DATINV */
+#define WM8904_ADCL_DATINV_WIDTH                     1  /* ADCL_DATINV */
+#define WM8904_ADCR_DATINV                      0x0001  /* ADCR_DATINV */
+#define WM8904_ADCR_DATINV_MASK                 0x0001  /* ADCR_DATINV */
+#define WM8904_ADCR_DATINV_SHIFT                     0  /* ADCR_DATINV */
+#define WM8904_ADCR_DATINV_WIDTH                     1  /* ADCR_DATINV */
+
+/*
+ * R39 (0x27) - Digital Microphone 0
+ */
+#define WM8904_DMIC_ENA                         0x1000  /* DMIC_ENA */
+#define WM8904_DMIC_ENA_MASK                    0x1000  /* DMIC_ENA */
+#define WM8904_DMIC_ENA_SHIFT                       12  /* DMIC_ENA */
+#define WM8904_DMIC_ENA_WIDTH                        1  /* DMIC_ENA */
+#define WM8904_DMIC_SRC                         0x0800  /* DMIC_SRC */
+#define WM8904_DMIC_SRC_MASK                    0x0800  /* DMIC_SRC */
+#define WM8904_DMIC_SRC_SHIFT                       11  /* DMIC_SRC */
+#define WM8904_DMIC_SRC_WIDTH                        1  /* DMIC_SRC */
+
+/*
+ * R40 (0x28) - DRC 0
+ */
+#define WM8904_DRC_ENA                          0x8000  /* DRC_ENA */
+#define WM8904_DRC_ENA_MASK                     0x8000  /* DRC_ENA */
+#define WM8904_DRC_ENA_SHIFT                        15  /* DRC_ENA */
+#define WM8904_DRC_ENA_WIDTH                         1  /* DRC_ENA */
+#define WM8904_DRC_DAC_PATH                     0x4000  /* DRC_DAC_PATH */
+#define WM8904_DRC_DAC_PATH_MASK                0x4000  /* DRC_DAC_PATH */
+#define WM8904_DRC_DAC_PATH_SHIFT                   14  /* DRC_DAC_PATH */
+#define WM8904_DRC_DAC_PATH_WIDTH                    1  /* DRC_DAC_PATH */
+#define WM8904_DRC_GS_HYST_LVL_MASK             0x1800  /* DRC_GS_HYST_LVL - [12:11] */
+#define WM8904_DRC_GS_HYST_LVL_SHIFT                11  /* DRC_GS_HYST_LVL - [12:11] */
+#define WM8904_DRC_GS_HYST_LVL_WIDTH                 2  /* DRC_GS_HYST_LVL - [12:11] */
+#define WM8904_DRC_STARTUP_GAIN_MASK            0x07C0  /* DRC_STARTUP_GAIN - [10:6] */
+#define WM8904_DRC_STARTUP_GAIN_SHIFT                6  /* DRC_STARTUP_GAIN - [10:6] */
+#define WM8904_DRC_STARTUP_GAIN_WIDTH                5  /* DRC_STARTUP_GAIN - [10:6] */
+#define WM8904_DRC_FF_DELAY                     0x0020  /* DRC_FF_DELAY */
+#define WM8904_DRC_FF_DELAY_MASK                0x0020  /* DRC_FF_DELAY */
+#define WM8904_DRC_FF_DELAY_SHIFT                    5  /* DRC_FF_DELAY */
+#define WM8904_DRC_FF_DELAY_WIDTH                    1  /* DRC_FF_DELAY */
+#define WM8904_DRC_GS_ENA                       0x0008  /* DRC_GS_ENA */
+#define WM8904_DRC_GS_ENA_MASK                  0x0008  /* DRC_GS_ENA */
+#define WM8904_DRC_GS_ENA_SHIFT                      3  /* DRC_GS_ENA */
+#define WM8904_DRC_GS_ENA_WIDTH                      1  /* DRC_GS_ENA */
+#define WM8904_DRC_QR                           0x0004  /* DRC_QR */
+#define WM8904_DRC_QR_MASK                      0x0004  /* DRC_QR */
+#define WM8904_DRC_QR_SHIFT                          2  /* DRC_QR */
+#define WM8904_DRC_QR_WIDTH                          1  /* DRC_QR */
+#define WM8904_DRC_ANTICLIP                     0x0002  /* DRC_ANTICLIP */
+#define WM8904_DRC_ANTICLIP_MASK                0x0002  /* DRC_ANTICLIP */
+#define WM8904_DRC_ANTICLIP_SHIFT                    1  /* DRC_ANTICLIP */
+#define WM8904_DRC_ANTICLIP_WIDTH                    1  /* DRC_ANTICLIP */
+#define WM8904_DRC_GS_HYST                      0x0001  /* DRC_GS_HYST */
+#define WM8904_DRC_GS_HYST_MASK                 0x0001  /* DRC_GS_HYST */
+#define WM8904_DRC_GS_HYST_SHIFT                     0  /* DRC_GS_HYST */
+#define WM8904_DRC_GS_HYST_WIDTH                     1  /* DRC_GS_HYST */
+
+/*
+ * R41 (0x29) - DRC 1
+ */
+#define WM8904_DRC_ATK_MASK                     0xF000  /* DRC_ATK - [15:12] */
+#define WM8904_DRC_ATK_SHIFT                        12  /* DRC_ATK - [15:12] */
+#define WM8904_DRC_ATK_WIDTH                         4  /* DRC_ATK - [15:12] */
+#define WM8904_DRC_DCY_MASK                     0x0F00  /* DRC_DCY - [11:8] */
+#define WM8904_DRC_DCY_SHIFT                         8  /* DRC_DCY - [11:8] */
+#define WM8904_DRC_DCY_WIDTH                         4  /* DRC_DCY - [11:8] */
+#define WM8904_DRC_QR_THR_MASK                  0x00C0  /* DRC_QR_THR - [7:6] */
+#define WM8904_DRC_QR_THR_SHIFT                      6  /* DRC_QR_THR - [7:6] */
+#define WM8904_DRC_QR_THR_WIDTH                      2  /* DRC_QR_THR - [7:6] */
+#define WM8904_DRC_QR_DCY_MASK                  0x0030  /* DRC_QR_DCY - [5:4] */
+#define WM8904_DRC_QR_DCY_SHIFT                      4  /* DRC_QR_DCY - [5:4] */
+#define WM8904_DRC_QR_DCY_WIDTH                      2  /* DRC_QR_DCY - [5:4] */
+#define WM8904_DRC_MINGAIN_MASK                 0x000C  /* DRC_MINGAIN - [3:2] */
+#define WM8904_DRC_MINGAIN_SHIFT                     2  /* DRC_MINGAIN - [3:2] */
+#define WM8904_DRC_MINGAIN_WIDTH                     2  /* DRC_MINGAIN - [3:2] */
+#define WM8904_DRC_MAXGAIN_MASK                 0x0003  /* DRC_MAXGAIN - [1:0] */
+#define WM8904_DRC_MAXGAIN_SHIFT                     0  /* DRC_MAXGAIN - [1:0] */
+#define WM8904_DRC_MAXGAIN_WIDTH                     2  /* DRC_MAXGAIN - [1:0] */
+
+/*
+ * R42 (0x2A) - DRC 2
+ */
+#define WM8904_DRC_HI_COMP_MASK                 0x0038  /* DRC_HI_COMP - [5:3] */
+#define WM8904_DRC_HI_COMP_SHIFT                     3  /* DRC_HI_COMP - [5:3] */
+#define WM8904_DRC_HI_COMP_WIDTH                     3  /* DRC_HI_COMP - [5:3] */
+#define WM8904_DRC_LO_COMP_MASK                 0x0007  /* DRC_LO_COMP - [2:0] */
+#define WM8904_DRC_LO_COMP_SHIFT                     0  /* DRC_LO_COMP - [2:0] */
+#define WM8904_DRC_LO_COMP_WIDTH                     3  /* DRC_LO_COMP - [2:0] */
+
+/*
+ * R43 (0x2B) - DRC 3
+ */
+#define WM8904_DRC_KNEE_IP_MASK                 0x07E0  /* DRC_KNEE_IP - [10:5] */
+#define WM8904_DRC_KNEE_IP_SHIFT                     5  /* DRC_KNEE_IP - [10:5] */
+#define WM8904_DRC_KNEE_IP_WIDTH                     6  /* DRC_KNEE_IP - [10:5] */
+#define WM8904_DRC_KNEE_OP_MASK                 0x001F  /* DRC_KNEE_OP - [4:0] */
+#define WM8904_DRC_KNEE_OP_SHIFT                     0  /* DRC_KNEE_OP - [4:0] */
+#define WM8904_DRC_KNEE_OP_WIDTH                     5  /* DRC_KNEE_OP - [4:0] */
+
+/*
+ * R44 (0x2C) - Analogue Left Input 0
+ */
+#define WM8904_LINMUTE                          0x0080  /* LINMUTE */
+#define WM8904_LINMUTE_MASK                     0x0080  /* LINMUTE */
+#define WM8904_LINMUTE_SHIFT                         7  /* LINMUTE */
+#define WM8904_LINMUTE_WIDTH                         1  /* LINMUTE */
+#define WM8904_LIN_VOL_MASK                     0x001F  /* LIN_VOL - [4:0] */
+#define WM8904_LIN_VOL_SHIFT                         0  /* LIN_VOL - [4:0] */
+#define WM8904_LIN_VOL_WIDTH                         5  /* LIN_VOL - [4:0] */
+
+/*
+ * R45 (0x2D) - Analogue Right Input 0
+ */
+#define WM8904_RINMUTE                          0x0080  /* RINMUTE */
+#define WM8904_RINMUTE_MASK                     0x0080  /* RINMUTE */
+#define WM8904_RINMUTE_SHIFT                         7  /* RINMUTE */
+#define WM8904_RINMUTE_WIDTH                         1  /* RINMUTE */
+#define WM8904_RIN_VOL_MASK                     0x001F  /* RIN_VOL - [4:0] */
+#define WM8904_RIN_VOL_SHIFT                         0  /* RIN_VOL - [4:0] */
+#define WM8904_RIN_VOL_WIDTH                         5  /* RIN_VOL - [4:0] */
+
+/*
+ * R46 (0x2E) - Analogue Left Input 1
+ */
+#define WM8904_INL_CM_ENA                       0x0040  /* INL_CM_ENA */
+#define WM8904_INL_CM_ENA_MASK                  0x0040  /* INL_CM_ENA */
+#define WM8904_INL_CM_ENA_SHIFT                      6  /* INL_CM_ENA */
+#define WM8904_INL_CM_ENA_WIDTH                      1  /* INL_CM_ENA */
+#define WM8904_L_IP_SEL_N_MASK                  0x0030  /* L_IP_SEL_N - [5:4] */
+#define WM8904_L_IP_SEL_N_SHIFT                      4  /* L_IP_SEL_N - [5:4] */
+#define WM8904_L_IP_SEL_N_WIDTH                      2  /* L_IP_SEL_N - [5:4] */
+#define WM8904_L_IP_SEL_P_MASK                  0x000C  /* L_IP_SEL_P - [3:2] */
+#define WM8904_L_IP_SEL_P_SHIFT                      2  /* L_IP_SEL_P - [3:2] */
+#define WM8904_L_IP_SEL_P_WIDTH                      2  /* L_IP_SEL_P - [3:2] */
+#define WM8904_L_MODE_MASK                      0x0003  /* L_MODE - [1:0] */
+#define WM8904_L_MODE_SHIFT                          0  /* L_MODE - [1:0] */
+#define WM8904_L_MODE_WIDTH                          2  /* L_MODE - [1:0] */
+
+/*
+ * R47 (0x2F) - Analogue Right Input 1
+ */
+#define WM8904_INR_CM_ENA                       0x0040  /* INR_CM_ENA */
+#define WM8904_INR_CM_ENA_MASK                  0x0040  /* INR_CM_ENA */
+#define WM8904_INR_CM_ENA_SHIFT                      6  /* INR_CM_ENA */
+#define WM8904_INR_CM_ENA_WIDTH                      1  /* INR_CM_ENA */
+#define WM8904_R_IP_SEL_N_MASK                  0x0030  /* R_IP_SEL_N - [5:4] */
+#define WM8904_R_IP_SEL_N_SHIFT                      4  /* R_IP_SEL_N - [5:4] */
+#define WM8904_R_IP_SEL_N_WIDTH                      2  /* R_IP_SEL_N - [5:4] */
+#define WM8904_R_IP_SEL_P_MASK                  0x000C  /* R_IP_SEL_P - [3:2] */
+#define WM8904_R_IP_SEL_P_SHIFT                      2  /* R_IP_SEL_P - [3:2] */
+#define WM8904_R_IP_SEL_P_WIDTH                      2  /* R_IP_SEL_P - [3:2] */
+#define WM8904_R_MODE_MASK                      0x0003  /* R_MODE - [1:0] */
+#define WM8904_R_MODE_SHIFT                          0  /* R_MODE - [1:0] */
+#define WM8904_R_MODE_WIDTH                          2  /* R_MODE - [1:0] */
+
+/*
+ * R57 (0x39) - Analogue OUT1 Left
+ */
+#define WM8904_HPOUTL_MUTE                      0x0100  /* HPOUTL_MUTE */
+#define WM8904_HPOUTL_MUTE_MASK                 0x0100  /* HPOUTL_MUTE */
+#define WM8904_HPOUTL_MUTE_SHIFT                     8  /* HPOUTL_MUTE */
+#define WM8904_HPOUTL_MUTE_WIDTH                     1  /* HPOUTL_MUTE */
+#define WM8904_HPOUT_VU                         0x0080  /* HPOUT_VU */
+#define WM8904_HPOUT_VU_MASK                    0x0080  /* HPOUT_VU */
+#define WM8904_HPOUT_VU_SHIFT                        7  /* HPOUT_VU */
+#define WM8904_HPOUT_VU_WIDTH                        1  /* HPOUT_VU */
+#define WM8904_HPOUTLZC                         0x0040  /* HPOUTLZC */
+#define WM8904_HPOUTLZC_MASK                    0x0040  /* HPOUTLZC */
+#define WM8904_HPOUTLZC_SHIFT                        6  /* HPOUTLZC */
+#define WM8904_HPOUTLZC_WIDTH                        1  /* HPOUTLZC */
+#define WM8904_HPOUTL_VOL_MASK                  0x003F  /* HPOUTL_VOL - [5:0] */
+#define WM8904_HPOUTL_VOL_SHIFT                      0  /* HPOUTL_VOL - [5:0] */
+#define WM8904_HPOUTL_VOL_WIDTH                      6  /* HPOUTL_VOL - [5:0] */
+
+/*
+ * R58 (0x3A) - Analogue OUT1 Right
+ */
+#define WM8904_HPOUTR_MUTE                      0x0100  /* HPOUTR_MUTE */
+#define WM8904_HPOUTR_MUTE_MASK                 0x0100  /* HPOUTR_MUTE */
+#define WM8904_HPOUTR_MUTE_SHIFT                     8  /* HPOUTR_MUTE */
+#define WM8904_HPOUTR_MUTE_WIDTH                     1  /* HPOUTR_MUTE */
+#define WM8904_HPOUT_VU                         0x0080  /* HPOUT_VU */
+#define WM8904_HPOUT_VU_MASK                    0x0080  /* HPOUT_VU */
+#define WM8904_HPOUT_VU_SHIFT                        7  /* HPOUT_VU */
+#define WM8904_HPOUT_VU_WIDTH                        1  /* HPOUT_VU */
+#define WM8904_HPOUTRZC                         0x0040  /* HPOUTRZC */
+#define WM8904_HPOUTRZC_MASK                    0x0040  /* HPOUTRZC */
+#define WM8904_HPOUTRZC_SHIFT                        6  /* HPOUTRZC */
+#define WM8904_HPOUTRZC_WIDTH                        1  /* HPOUTRZC */
+#define WM8904_HPOUTR_VOL_MASK                  0x003F  /* HPOUTR_VOL - [5:0] */
+#define WM8904_HPOUTR_VOL_SHIFT                      0  /* HPOUTR_VOL - [5:0] */
+#define WM8904_HPOUTR_VOL_WIDTH                      6  /* HPOUTR_VOL - [5:0] */
+
+/*
+ * R59 (0x3B) - Analogue OUT2 Left
+ */
+#define WM8904_LINEOUTL_MUTE                    0x0100  /* LINEOUTL_MUTE */
+#define WM8904_LINEOUTL_MUTE_MASK               0x0100  /* LINEOUTL_MUTE */
+#define WM8904_LINEOUTL_MUTE_SHIFT                   8  /* LINEOUTL_MUTE */
+#define WM8904_LINEOUTL_MUTE_WIDTH                   1  /* LINEOUTL_MUTE */
+#define WM8904_LINEOUT_VU                       0x0080  /* LINEOUT_VU */
+#define WM8904_LINEOUT_VU_MASK                  0x0080  /* LINEOUT_VU */
+#define WM8904_LINEOUT_VU_SHIFT                      7  /* LINEOUT_VU */
+#define WM8904_LINEOUT_VU_WIDTH                      1  /* LINEOUT_VU */
+#define WM8904_LINEOUTLZC                       0x0040  /* LINEOUTLZC */
+#define WM8904_LINEOUTLZC_MASK                  0x0040  /* LINEOUTLZC */
+#define WM8904_LINEOUTLZC_SHIFT                      6  /* LINEOUTLZC */
+#define WM8904_LINEOUTLZC_WIDTH                      1  /* LINEOUTLZC */
+#define WM8904_LINEOUTL_VOL_MASK                0x003F  /* LINEOUTL_VOL - [5:0] */
+#define WM8904_LINEOUTL_VOL_SHIFT                    0  /* LINEOUTL_VOL - [5:0] */
+#define WM8904_LINEOUTL_VOL_WIDTH                    6  /* LINEOUTL_VOL - [5:0] */
+
+/*
+ * R60 (0x3C) - Analogue OUT2 Right
+ */
+#define WM8904_LINEOUTR_MUTE                    0x0100  /* LINEOUTR_MUTE */
+#define WM8904_LINEOUTR_MUTE_MASK               0x0100  /* LINEOUTR_MUTE */
+#define WM8904_LINEOUTR_MUTE_SHIFT                   8  /* LINEOUTR_MUTE */
+#define WM8904_LINEOUTR_MUTE_WIDTH                   1  /* LINEOUTR_MUTE */
+#define WM8904_LINEOUT_VU                       0x0080  /* LINEOUT_VU */
+#define WM8904_LINEOUT_VU_MASK                  0x0080  /* LINEOUT_VU */
+#define WM8904_LINEOUT_VU_SHIFT                      7  /* LINEOUT_VU */
+#define WM8904_LINEOUT_VU_WIDTH                      1  /* LINEOUT_VU */
+#define WM8904_LINEOUTRZC                       0x0040  /* LINEOUTRZC */
+#define WM8904_LINEOUTRZC_MASK                  0x0040  /* LINEOUTRZC */
+#define WM8904_LINEOUTRZC_SHIFT                      6  /* LINEOUTRZC */
+#define WM8904_LINEOUTRZC_WIDTH                      1  /* LINEOUTRZC */
+#define WM8904_LINEOUTR_VOL_MASK                0x003F  /* LINEOUTR_VOL - [5:0] */
+#define WM8904_LINEOUTR_VOL_SHIFT                    0  /* LINEOUTR_VOL - [5:0] */
+#define WM8904_LINEOUTR_VOL_WIDTH                    6  /* LINEOUTR_VOL - [5:0] */
+
+/*
+ * R61 (0x3D) - Analogue OUT12 ZC
+ */
+#define WM8904_HPL_BYP_ENA                      0x0008  /* HPL_BYP_ENA */
+#define WM8904_HPL_BYP_ENA_MASK                 0x0008  /* HPL_BYP_ENA */
+#define WM8904_HPL_BYP_ENA_SHIFT                     3  /* HPL_BYP_ENA */
+#define WM8904_HPL_BYP_ENA_WIDTH                     1  /* HPL_BYP_ENA */
+#define WM8904_HPR_BYP_ENA                      0x0004  /* HPR_BYP_ENA */
+#define WM8904_HPR_BYP_ENA_MASK                 0x0004  /* HPR_BYP_ENA */
+#define WM8904_HPR_BYP_ENA_SHIFT                     2  /* HPR_BYP_ENA */
+#define WM8904_HPR_BYP_ENA_WIDTH                     1  /* HPR_BYP_ENA */
+#define WM8904_LINEOUTL_BYP_ENA                 0x0002  /* LINEOUTL_BYP_ENA */
+#define WM8904_LINEOUTL_BYP_ENA_MASK            0x0002  /* LINEOUTL_BYP_ENA */
+#define WM8904_LINEOUTL_BYP_ENA_SHIFT                1  /* LINEOUTL_BYP_ENA */
+#define WM8904_LINEOUTL_BYP_ENA_WIDTH                1  /* LINEOUTL_BYP_ENA */
+#define WM8904_LINEOUTR_BYP_ENA                 0x0001  /* LINEOUTR_BYP_ENA */
+#define WM8904_LINEOUTR_BYP_ENA_MASK            0x0001  /* LINEOUTR_BYP_ENA */
+#define WM8904_LINEOUTR_BYP_ENA_SHIFT                0  /* LINEOUTR_BYP_ENA */
+#define WM8904_LINEOUTR_BYP_ENA_WIDTH                1  /* LINEOUTR_BYP_ENA */
+
+/*
+ * R67 (0x43) - DC Servo 0
+ */
+#define WM8904_DCS_ENA_CHAN_3                   0x0008  /* DCS_ENA_CHAN_3 */
+#define WM8904_DCS_ENA_CHAN_3_MASK              0x0008  /* DCS_ENA_CHAN_3 */
+#define WM8904_DCS_ENA_CHAN_3_SHIFT                  3  /* DCS_ENA_CHAN_3 */
+#define WM8904_DCS_ENA_CHAN_3_WIDTH                  1  /* DCS_ENA_CHAN_3 */
+#define WM8904_DCS_ENA_CHAN_2                   0x0004  /* DCS_ENA_CHAN_2 */
+#define WM8904_DCS_ENA_CHAN_2_MASK              0x0004  /* DCS_ENA_CHAN_2 */
+#define WM8904_DCS_ENA_CHAN_2_SHIFT                  2  /* DCS_ENA_CHAN_2 */
+#define WM8904_DCS_ENA_CHAN_2_WIDTH                  1  /* DCS_ENA_CHAN_2 */
+#define WM8904_DCS_ENA_CHAN_1                   0x0002  /* DCS_ENA_CHAN_1 */
+#define WM8904_DCS_ENA_CHAN_1_MASK              0x0002  /* DCS_ENA_CHAN_1 */
+#define WM8904_DCS_ENA_CHAN_1_SHIFT                  1  /* DCS_ENA_CHAN_1 */
+#define WM8904_DCS_ENA_CHAN_1_WIDTH                  1  /* DCS_ENA_CHAN_1 */
+#define WM8904_DCS_ENA_CHAN_0                   0x0001  /* DCS_ENA_CHAN_0 */
+#define WM8904_DCS_ENA_CHAN_0_MASK              0x0001  /* DCS_ENA_CHAN_0 */
+#define WM8904_DCS_ENA_CHAN_0_SHIFT                  0  /* DCS_ENA_CHAN_0 */
+#define WM8904_DCS_ENA_CHAN_0_WIDTH                  1  /* DCS_ENA_CHAN_0 */
+
+/*
+ * R68 (0x44) - DC Servo 1
+ */
+#define WM8904_DCS_TRIG_SINGLE_3                0x8000  /* DCS_TRIG_SINGLE_3 */
+#define WM8904_DCS_TRIG_SINGLE_3_MASK           0x8000  /* DCS_TRIG_SINGLE_3 */
+#define WM8904_DCS_TRIG_SINGLE_3_SHIFT              15  /* DCS_TRIG_SINGLE_3 */
+#define WM8904_DCS_TRIG_SINGLE_3_WIDTH               1  /* DCS_TRIG_SINGLE_3 */
+#define WM8904_DCS_TRIG_SINGLE_2                0x4000  /* DCS_TRIG_SINGLE_2 */
+#define WM8904_DCS_TRIG_SINGLE_2_MASK           0x4000  /* DCS_TRIG_SINGLE_2 */
+#define WM8904_DCS_TRIG_SINGLE_2_SHIFT              14  /* DCS_TRIG_SINGLE_2 */
+#define WM8904_DCS_TRIG_SINGLE_2_WIDTH               1  /* DCS_TRIG_SINGLE_2 */
+#define WM8904_DCS_TRIG_SINGLE_1                0x2000  /* DCS_TRIG_SINGLE_1 */
+#define WM8904_DCS_TRIG_SINGLE_1_MASK           0x2000  /* DCS_TRIG_SINGLE_1 */
+#define WM8904_DCS_TRIG_SINGLE_1_SHIFT              13  /* DCS_TRIG_SINGLE_1 */
+#define WM8904_DCS_TRIG_SINGLE_1_WIDTH               1  /* DCS_TRIG_SINGLE_1 */
+#define WM8904_DCS_TRIG_SINGLE_0                0x1000  /* DCS_TRIG_SINGLE_0 */
+#define WM8904_DCS_TRIG_SINGLE_0_MASK           0x1000  /* DCS_TRIG_SINGLE_0 */
+#define WM8904_DCS_TRIG_SINGLE_0_SHIFT              12  /* DCS_TRIG_SINGLE_0 */
+#define WM8904_DCS_TRIG_SINGLE_0_WIDTH               1  /* DCS_TRIG_SINGLE_0 */
+#define WM8904_DCS_TRIG_SERIES_3                0x0800  /* DCS_TRIG_SERIES_3 */
+#define WM8904_DCS_TRIG_SERIES_3_MASK           0x0800  /* DCS_TRIG_SERIES_3 */
+#define WM8904_DCS_TRIG_SERIES_3_SHIFT              11  /* DCS_TRIG_SERIES_3 */
+#define WM8904_DCS_TRIG_SERIES_3_WIDTH               1  /* DCS_TRIG_SERIES_3 */
+#define WM8904_DCS_TRIG_SERIES_2                0x0400  /* DCS_TRIG_SERIES_2 */
+#define WM8904_DCS_TRIG_SERIES_2_MASK           0x0400  /* DCS_TRIG_SERIES_2 */
+#define WM8904_DCS_TRIG_SERIES_2_SHIFT              10  /* DCS_TRIG_SERIES_2 */
+#define WM8904_DCS_TRIG_SERIES_2_WIDTH               1  /* DCS_TRIG_SERIES_2 */
+#define WM8904_DCS_TRIG_SERIES_1                0x0200  /* DCS_TRIG_SERIES_1 */
+#define WM8904_DCS_TRIG_SERIES_1_MASK           0x0200  /* DCS_TRIG_SERIES_1 */
+#define WM8904_DCS_TRIG_SERIES_1_SHIFT               9  /* DCS_TRIG_SERIES_1 */
+#define WM8904_DCS_TRIG_SERIES_1_WIDTH               1  /* DCS_TRIG_SERIES_1 */
+#define WM8904_DCS_TRIG_SERIES_0                0x0100  /* DCS_TRIG_SERIES_0 */
+#define WM8904_DCS_TRIG_SERIES_0_MASK           0x0100  /* DCS_TRIG_SERIES_0 */
+#define WM8904_DCS_TRIG_SERIES_0_SHIFT               8  /* DCS_TRIG_SERIES_0 */
+#define WM8904_DCS_TRIG_SERIES_0_WIDTH               1  /* DCS_TRIG_SERIES_0 */
+#define WM8904_DCS_TRIG_STARTUP_3               0x0080  /* DCS_TRIG_STARTUP_3 */
+#define WM8904_DCS_TRIG_STARTUP_3_MASK          0x0080  /* DCS_TRIG_STARTUP_3 */
+#define WM8904_DCS_TRIG_STARTUP_3_SHIFT              7  /* DCS_TRIG_STARTUP_3 */
+#define WM8904_DCS_TRIG_STARTUP_3_WIDTH              1  /* DCS_TRIG_STARTUP_3 */
+#define WM8904_DCS_TRIG_STARTUP_2               0x0040  /* DCS_TRIG_STARTUP_2 */
+#define WM8904_DCS_TRIG_STARTUP_2_MASK          0x0040  /* DCS_TRIG_STARTUP_2 */
+#define WM8904_DCS_TRIG_STARTUP_2_SHIFT              6  /* DCS_TRIG_STARTUP_2 */
+#define WM8904_DCS_TRIG_STARTUP_2_WIDTH              1  /* DCS_TRIG_STARTUP_2 */
+#define WM8904_DCS_TRIG_STARTUP_1               0x0020  /* DCS_TRIG_STARTUP_1 */
+#define WM8904_DCS_TRIG_STARTUP_1_MASK          0x0020  /* DCS_TRIG_STARTUP_1 */
+#define WM8904_DCS_TRIG_STARTUP_1_SHIFT              5  /* DCS_TRIG_STARTUP_1 */
+#define WM8904_DCS_TRIG_STARTUP_1_WIDTH              1  /* DCS_TRIG_STARTUP_1 */
+#define WM8904_DCS_TRIG_STARTUP_0               0x0010  /* DCS_TRIG_STARTUP_0 */
+#define WM8904_DCS_TRIG_STARTUP_0_MASK          0x0010  /* DCS_TRIG_STARTUP_0 */
+#define WM8904_DCS_TRIG_STARTUP_0_SHIFT              4  /* DCS_TRIG_STARTUP_0 */
+#define WM8904_DCS_TRIG_STARTUP_0_WIDTH              1  /* DCS_TRIG_STARTUP_0 */
+#define WM8904_DCS_TRIG_DAC_WR_3                0x0008  /* DCS_TRIG_DAC_WR_3 */
+#define WM8904_DCS_TRIG_DAC_WR_3_MASK           0x0008  /* DCS_TRIG_DAC_WR_3 */
+#define WM8904_DCS_TRIG_DAC_WR_3_SHIFT               3  /* DCS_TRIG_DAC_WR_3 */
+#define WM8904_DCS_TRIG_DAC_WR_3_WIDTH               1  /* DCS_TRIG_DAC_WR_3 */
+#define WM8904_DCS_TRIG_DAC_WR_2                0x0004  /* DCS_TRIG_DAC_WR_2 */
+#define WM8904_DCS_TRIG_DAC_WR_2_MASK           0x0004  /* DCS_TRIG_DAC_WR_2 */
+#define WM8904_DCS_TRIG_DAC_WR_2_SHIFT               2  /* DCS_TRIG_DAC_WR_2 */
+#define WM8904_DCS_TRIG_DAC_WR_2_WIDTH               1  /* DCS_TRIG_DAC_WR_2 */
+#define WM8904_DCS_TRIG_DAC_WR_1                0x0002  /* DCS_TRIG_DAC_WR_1 */
+#define WM8904_DCS_TRIG_DAC_WR_1_MASK           0x0002  /* DCS_TRIG_DAC_WR_1 */
+#define WM8904_DCS_TRIG_DAC_WR_1_SHIFT               1  /* DCS_TRIG_DAC_WR_1 */
+#define WM8904_DCS_TRIG_DAC_WR_1_WIDTH               1  /* DCS_TRIG_DAC_WR_1 */
+#define WM8904_DCS_TRIG_DAC_WR_0                0x0001  /* DCS_TRIG_DAC_WR_0 */
+#define WM8904_DCS_TRIG_DAC_WR_0_MASK           0x0001  /* DCS_TRIG_DAC_WR_0 */
+#define WM8904_DCS_TRIG_DAC_WR_0_SHIFT               0  /* DCS_TRIG_DAC_WR_0 */
+#define WM8904_DCS_TRIG_DAC_WR_0_WIDTH               1  /* DCS_TRIG_DAC_WR_0 */
+
+/*
+ * R69 (0x45) - DC Servo 2
+ */
+#define WM8904_DCS_TIMER_PERIOD_23_MASK         0x0F00  /* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8904_DCS_TIMER_PERIOD_23_SHIFT             8  /* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8904_DCS_TIMER_PERIOD_23_WIDTH             4  /* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8904_DCS_TIMER_PERIOD_01_MASK         0x000F  /* DCS_TIMER_PERIOD_01 - [3:0] */
+#define WM8904_DCS_TIMER_PERIOD_01_SHIFT             0  /* DCS_TIMER_PERIOD_01 - [3:0] */
+#define WM8904_DCS_TIMER_PERIOD_01_WIDTH             4  /* DCS_TIMER_PERIOD_01 - [3:0] */
+
+/*
+ * R71 (0x47) - DC Servo 4
+ */
+#define WM8904_DCS_SERIES_NO_23_MASK            0x007F  /* DCS_SERIES_NO_23 - [6:0] */
+#define WM8904_DCS_SERIES_NO_23_SHIFT                0  /* DCS_SERIES_NO_23 - [6:0] */
+#define WM8904_DCS_SERIES_NO_23_WIDTH                7  /* DCS_SERIES_NO_23 - [6:0] */
+
+/*
+ * R72 (0x48) - DC Servo 5
+ */
+#define WM8904_DCS_SERIES_NO_01_MASK            0x007F  /* DCS_SERIES_NO_01 - [6:0] */
+#define WM8904_DCS_SERIES_NO_01_SHIFT                0  /* DCS_SERIES_NO_01 - [6:0] */
+#define WM8904_DCS_SERIES_NO_01_WIDTH                7  /* DCS_SERIES_NO_01 - [6:0] */
+
+/*
+ * R73 (0x49) - DC Servo 6
+ */
+#define WM8904_DCS_DAC_WR_VAL_3_MASK            0x00FF  /* DCS_DAC_WR_VAL_3 - [7:0] */
+#define WM8904_DCS_DAC_WR_VAL_3_SHIFT                0  /* DCS_DAC_WR_VAL_3 - [7:0] */
+#define WM8904_DCS_DAC_WR_VAL_3_WIDTH                8  /* DCS_DAC_WR_VAL_3 - [7:0] */
+
+/*
+ * R74 (0x4A) - DC Servo 7
+ */
+#define WM8904_DCS_DAC_WR_VAL_2_MASK            0x00FF  /* DCS_DAC_WR_VAL_2 - [7:0] */
+#define WM8904_DCS_DAC_WR_VAL_2_SHIFT                0  /* DCS_DAC_WR_VAL_2 - [7:0] */
+#define WM8904_DCS_DAC_WR_VAL_2_WIDTH                8  /* DCS_DAC_WR_VAL_2 - [7:0] */
+
+/*
+ * R75 (0x4B) - DC Servo 8
+ */
+#define WM8904_DCS_DAC_WR_VAL_1_MASK            0x00FF  /* DCS_DAC_WR_VAL_1 - [7:0] */
+#define WM8904_DCS_DAC_WR_VAL_1_SHIFT                0  /* DCS_DAC_WR_VAL_1 - [7:0] */
+#define WM8904_DCS_DAC_WR_VAL_1_WIDTH                8  /* DCS_DAC_WR_VAL_1 - [7:0] */
+
+/*
+ * R76 (0x4C) - DC Servo 9
+ */
+#define WM8904_DCS_DAC_WR_VAL_0_MASK            0x00FF  /* DCS_DAC_WR_VAL_0 - [7:0] */
+#define WM8904_DCS_DAC_WR_VAL_0_SHIFT                0  /* DCS_DAC_WR_VAL_0 - [7:0] */
+#define WM8904_DCS_DAC_WR_VAL_0_WIDTH                8  /* DCS_DAC_WR_VAL_0 - [7:0] */
+
+/*
+ * R77 (0x4D) - DC Servo Readback 0
+ */
+#define WM8904_DCS_CAL_COMPLETE_MASK            0x0F00  /* DCS_CAL_COMPLETE - [11:8] */
+#define WM8904_DCS_CAL_COMPLETE_SHIFT                8  /* DCS_CAL_COMPLETE - [11:8] */
+#define WM8904_DCS_CAL_COMPLETE_WIDTH                4  /* DCS_CAL_COMPLETE - [11:8] */
+#define WM8904_DCS_DAC_WR_COMPLETE_MASK         0x00F0  /* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8904_DCS_DAC_WR_COMPLETE_SHIFT             4  /* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8904_DCS_DAC_WR_COMPLETE_WIDTH             4  /* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8904_DCS_STARTUP_COMPLETE_MASK        0x000F  /* DCS_STARTUP_COMPLETE - [3:0] */
+#define WM8904_DCS_STARTUP_COMPLETE_SHIFT            0  /* DCS_STARTUP_COMPLETE - [3:0] */
+#define WM8904_DCS_STARTUP_COMPLETE_WIDTH            4  /* DCS_STARTUP_COMPLETE - [3:0] */
+
+/*
+ * R90 (0x5A) - Analogue HP 0
+ */
+#define WM8904_HPL_RMV_SHORT                    0x0080  /* HPL_RMV_SHORT */
+#define WM8904_HPL_RMV_SHORT_MASK               0x0080  /* HPL_RMV_SHORT */
+#define WM8904_HPL_RMV_SHORT_SHIFT                   7  /* HPL_RMV_SHORT */
+#define WM8904_HPL_RMV_SHORT_WIDTH                   1  /* HPL_RMV_SHORT */
+#define WM8904_HPL_ENA_OUTP                     0x0040  /* HPL_ENA_OUTP */
+#define WM8904_HPL_ENA_OUTP_MASK                0x0040  /* HPL_ENA_OUTP */
+#define WM8904_HPL_ENA_OUTP_SHIFT                    6  /* HPL_ENA_OUTP */
+#define WM8904_HPL_ENA_OUTP_WIDTH                    1  /* HPL_ENA_OUTP */
+#define WM8904_HPL_ENA_DLY                      0x0020  /* HPL_ENA_DLY */
+#define WM8904_HPL_ENA_DLY_MASK                 0x0020  /* HPL_ENA_DLY */
+#define WM8904_HPL_ENA_DLY_SHIFT                     5  /* HPL_ENA_DLY */
+#define WM8904_HPL_ENA_DLY_WIDTH                     1  /* HPL_ENA_DLY */
+#define WM8904_HPL_ENA                          0x0010  /* HPL_ENA */
+#define WM8904_HPL_ENA_MASK                     0x0010  /* HPL_ENA */
+#define WM8904_HPL_ENA_SHIFT                         4  /* HPL_ENA */
+#define WM8904_HPL_ENA_WIDTH                         1  /* HPL_ENA */
+#define WM8904_HPR_RMV_SHORT                    0x0008  /* HPR_RMV_SHORT */
+#define WM8904_HPR_RMV_SHORT_MASK               0x0008  /* HPR_RMV_SHORT */
+#define WM8904_HPR_RMV_SHORT_SHIFT                   3  /* HPR_RMV_SHORT */
+#define WM8904_HPR_RMV_SHORT_WIDTH                   1  /* HPR_RMV_SHORT */
+#define WM8904_HPR_ENA_OUTP                     0x0004  /* HPR_ENA_OUTP */
+#define WM8904_HPR_ENA_OUTP_MASK                0x0004  /* HPR_ENA_OUTP */
+#define WM8904_HPR_ENA_OUTP_SHIFT                    2  /* HPR_ENA_OUTP */
+#define WM8904_HPR_ENA_OUTP_WIDTH                    1  /* HPR_ENA_OUTP */
+#define WM8904_HPR_ENA_DLY                      0x0002  /* HPR_ENA_DLY */
+#define WM8904_HPR_ENA_DLY_MASK                 0x0002  /* HPR_ENA_DLY */
+#define WM8904_HPR_ENA_DLY_SHIFT                     1  /* HPR_ENA_DLY */
+#define WM8904_HPR_ENA_DLY_WIDTH                     1  /* HPR_ENA_DLY */
+#define WM8904_HPR_ENA                          0x0001  /* HPR_ENA */
+#define WM8904_HPR_ENA_MASK                     0x0001  /* HPR_ENA */
+#define WM8904_HPR_ENA_SHIFT                         0  /* HPR_ENA */
+#define WM8904_HPR_ENA_WIDTH                         1  /* HPR_ENA */
+
+/*
+ * R94 (0x5E) - Analogue Lineout 0
+ */
+#define WM8904_LINEOUTL_RMV_SHORT               0x0080  /* LINEOUTL_RMV_SHORT */
+#define WM8904_LINEOUTL_RMV_SHORT_MASK          0x0080  /* LINEOUTL_RMV_SHORT */
+#define WM8904_LINEOUTL_RMV_SHORT_SHIFT              7  /* LINEOUTL_RMV_SHORT */
+#define WM8904_LINEOUTL_RMV_SHORT_WIDTH              1  /* LINEOUTL_RMV_SHORT */
+#define WM8904_LINEOUTL_ENA_OUTP                0x0040  /* LINEOUTL_ENA_OUTP */
+#define WM8904_LINEOUTL_ENA_OUTP_MASK           0x0040  /* LINEOUTL_ENA_OUTP */
+#define WM8904_LINEOUTL_ENA_OUTP_SHIFT               6  /* LINEOUTL_ENA_OUTP */
+#define WM8904_LINEOUTL_ENA_OUTP_WIDTH               1  /* LINEOUTL_ENA_OUTP */
+#define WM8904_LINEOUTL_ENA_DLY                 0x0020  /* LINEOUTL_ENA_DLY */
+#define WM8904_LINEOUTL_ENA_DLY_MASK            0x0020  /* LINEOUTL_ENA_DLY */
+#define WM8904_LINEOUTL_ENA_DLY_SHIFT                5  /* LINEOUTL_ENA_DLY */
+#define WM8904_LINEOUTL_ENA_DLY_WIDTH                1  /* LINEOUTL_ENA_DLY */
+#define WM8904_LINEOUTL_ENA                     0x0010  /* LINEOUTL_ENA */
+#define WM8904_LINEOUTL_ENA_MASK                0x0010  /* LINEOUTL_ENA */
+#define WM8904_LINEOUTL_ENA_SHIFT                    4  /* LINEOUTL_ENA */
+#define WM8904_LINEOUTL_ENA_WIDTH                    1  /* LINEOUTL_ENA */
+#define WM8904_LINEOUTR_RMV_SHORT               0x0008  /* LINEOUTR_RMV_SHORT */
+#define WM8904_LINEOUTR_RMV_SHORT_MASK          0x0008  /* LINEOUTR_RMV_SHORT */
+#define WM8904_LINEOUTR_RMV_SHORT_SHIFT              3  /* LINEOUTR_RMV_SHORT */
+#define WM8904_LINEOUTR_RMV_SHORT_WIDTH              1  /* LINEOUTR_RMV_SHORT */
+#define WM8904_LINEOUTR_ENA_OUTP                0x0004  /* LINEOUTR_ENA_OUTP */
+#define WM8904_LINEOUTR_ENA_OUTP_MASK           0x0004  /* LINEOUTR_ENA_OUTP */
+#define WM8904_LINEOUTR_ENA_OUTP_SHIFT               2  /* LINEOUTR_ENA_OUTP */
+#define WM8904_LINEOUTR_ENA_OUTP_WIDTH               1  /* LINEOUTR_ENA_OUTP */
+#define WM8904_LINEOUTR_ENA_DLY                 0x0002  /* LINEOUTR_ENA_DLY */
+#define WM8904_LINEOUTR_ENA_DLY_MASK            0x0002  /* LINEOUTR_ENA_DLY */
+#define WM8904_LINEOUTR_ENA_DLY_SHIFT                1  /* LINEOUTR_ENA_DLY */
+#define WM8904_LINEOUTR_ENA_DLY_WIDTH                1  /* LINEOUTR_ENA_DLY */
+#define WM8904_LINEOUTR_ENA                     0x0001  /* LINEOUTR_ENA */
+#define WM8904_LINEOUTR_ENA_MASK                0x0001  /* LINEOUTR_ENA */
+#define WM8904_LINEOUTR_ENA_SHIFT                    0  /* LINEOUTR_ENA */
+#define WM8904_LINEOUTR_ENA_WIDTH                    1  /* LINEOUTR_ENA */
+
+/*
+ * R98 (0x62) - Charge Pump 0
+ */
+#define WM8904_CP_ENA                           0x0001  /* CP_ENA */
+#define WM8904_CP_ENA_MASK                      0x0001  /* CP_ENA */
+#define WM8904_CP_ENA_SHIFT                          0  /* CP_ENA */
+#define WM8904_CP_ENA_WIDTH                          1  /* CP_ENA */
+
+/*
+ * R104 (0x68) - Class W 0
+ */
+#define WM8904_CP_DYN_PWR                       0x0001  /* CP_DYN_PWR */
+#define WM8904_CP_DYN_PWR_MASK                  0x0001  /* CP_DYN_PWR */
+#define WM8904_CP_DYN_PWR_SHIFT                      0  /* CP_DYN_PWR */
+#define WM8904_CP_DYN_PWR_WIDTH                      1  /* CP_DYN_PWR */
+
+/*
+ * R108 (0x6C) - Write Sequencer 0
+ */
+#define WM8904_WSEQ_ENA                         0x0100  /* WSEQ_ENA */
+#define WM8904_WSEQ_ENA_MASK                    0x0100  /* WSEQ_ENA */
+#define WM8904_WSEQ_ENA_SHIFT                        8  /* WSEQ_ENA */
+#define WM8904_WSEQ_ENA_WIDTH                        1  /* WSEQ_ENA */
+#define WM8904_WSEQ_WRITE_INDEX_MASK            0x001F  /* WSEQ_WRITE_INDEX - [4:0] */
+#define WM8904_WSEQ_WRITE_INDEX_SHIFT                0  /* WSEQ_WRITE_INDEX - [4:0] */
+#define WM8904_WSEQ_WRITE_INDEX_WIDTH                5  /* WSEQ_WRITE_INDEX - [4:0] */
+
+/*
+ * R109 (0x6D) - Write Sequencer 1
+ */
+#define WM8904_WSEQ_DATA_WIDTH_MASK             0x7000  /* WSEQ_DATA_WIDTH - [14:12] */
+#define WM8904_WSEQ_DATA_WIDTH_SHIFT                12  /* WSEQ_DATA_WIDTH - [14:12] */
+#define WM8904_WSEQ_DATA_WIDTH_WIDTH                 3  /* WSEQ_DATA_WIDTH - [14:12] */
+#define WM8904_WSEQ_DATA_START_MASK             0x0F00  /* WSEQ_DATA_START - [11:8] */
+#define WM8904_WSEQ_DATA_START_SHIFT                 8  /* WSEQ_DATA_START - [11:8] */
+#define WM8904_WSEQ_DATA_START_WIDTH                 4  /* WSEQ_DATA_START - [11:8] */
+#define WM8904_WSEQ_ADDR_MASK                   0x00FF  /* WSEQ_ADDR - [7:0] */
+#define WM8904_WSEQ_ADDR_SHIFT                       0  /* WSEQ_ADDR - [7:0] */
+#define WM8904_WSEQ_ADDR_WIDTH                       8  /* WSEQ_ADDR - [7:0] */
+
+/*
+ * R110 (0x6E) - Write Sequencer 2
+ */
+#define WM8904_WSEQ_EOS                         0x4000  /* WSEQ_EOS */
+#define WM8904_WSEQ_EOS_MASK                    0x4000  /* WSEQ_EOS */
+#define WM8904_WSEQ_EOS_SHIFT                       14  /* WSEQ_EOS */
+#define WM8904_WSEQ_EOS_WIDTH                        1  /* WSEQ_EOS */
+#define WM8904_WSEQ_DELAY_MASK                  0x0F00  /* WSEQ_DELAY - [11:8] */
+#define WM8904_WSEQ_DELAY_SHIFT                      8  /* WSEQ_DELAY - [11:8] */
+#define WM8904_WSEQ_DELAY_WIDTH                      4  /* WSEQ_DELAY - [11:8] */
+#define WM8904_WSEQ_DATA_MASK                   0x00FF  /* WSEQ_DATA - [7:0] */
+#define WM8904_WSEQ_DATA_SHIFT                       0  /* WSEQ_DATA - [7:0] */
+#define WM8904_WSEQ_DATA_WIDTH                       8  /* WSEQ_DATA - [7:0] */
+
+/*
+ * R111 (0x6F) - Write Sequencer 3
+ */
+#define WM8904_WSEQ_ABORT                       0x0200  /* WSEQ_ABORT */
+#define WM8904_WSEQ_ABORT_MASK                  0x0200  /* WSEQ_ABORT */
+#define WM8904_WSEQ_ABORT_SHIFT                      9  /* WSEQ_ABORT */
+#define WM8904_WSEQ_ABORT_WIDTH                      1  /* WSEQ_ABORT */
+#define WM8904_WSEQ_START                       0x0100  /* WSEQ_START */
+#define WM8904_WSEQ_START_MASK                  0x0100  /* WSEQ_START */
+#define WM8904_WSEQ_START_SHIFT                      8  /* WSEQ_START */
+#define WM8904_WSEQ_START_WIDTH                      1  /* WSEQ_START */
+#define WM8904_WSEQ_START_INDEX_MASK            0x003F  /* WSEQ_START_INDEX - [5:0] */
+#define WM8904_WSEQ_START_INDEX_SHIFT                0  /* WSEQ_START_INDEX - [5:0] */
+#define WM8904_WSEQ_START_INDEX_WIDTH                6  /* WSEQ_START_INDEX - [5:0] */
+
+/*
+ * R112 (0x70) - Write Sequencer 4
+ */
+#define WM8904_WSEQ_CURRENT_INDEX_MASK          0x03F0  /* WSEQ_CURRENT_INDEX - [9:4] */
+#define WM8904_WSEQ_CURRENT_INDEX_SHIFT              4  /* WSEQ_CURRENT_INDEX - [9:4] */
+#define WM8904_WSEQ_CURRENT_INDEX_WIDTH              6  /* WSEQ_CURRENT_INDEX - [9:4] */
+#define WM8904_WSEQ_BUSY                        0x0001  /* WSEQ_BUSY */
+#define WM8904_WSEQ_BUSY_MASK                   0x0001  /* WSEQ_BUSY */
+#define WM8904_WSEQ_BUSY_SHIFT                       0  /* WSEQ_BUSY */
+#define WM8904_WSEQ_BUSY_WIDTH                       1  /* WSEQ_BUSY */
+
+/*
+ * R116 (0x74) - FLL Control 1
+ */
+#define WM8904_FLL_FRACN_ENA                    0x0004  /* FLL_FRACN_ENA */
+#define WM8904_FLL_FRACN_ENA_MASK               0x0004  /* FLL_FRACN_ENA */
+#define WM8904_FLL_FRACN_ENA_SHIFT                   2  /* FLL_FRACN_ENA */
+#define WM8904_FLL_FRACN_ENA_WIDTH                   1  /* FLL_FRACN_ENA */
+#define WM8904_FLL_OSC_ENA                      0x0002  /* FLL_OSC_ENA */
+#define WM8904_FLL_OSC_ENA_MASK                 0x0002  /* FLL_OSC_ENA */
+#define WM8904_FLL_OSC_ENA_SHIFT                     1  /* FLL_OSC_ENA */
+#define WM8904_FLL_OSC_ENA_WIDTH                     1  /* FLL_OSC_ENA */
+#define WM8904_FLL_ENA                          0x0001  /* FLL_ENA */
+#define WM8904_FLL_ENA_MASK                     0x0001  /* FLL_ENA */
+#define WM8904_FLL_ENA_SHIFT                         0  /* FLL_ENA */
+#define WM8904_FLL_ENA_WIDTH                         1  /* FLL_ENA */
+
+/*
+ * R117 (0x75) - FLL Control 2
+ */
+#define WM8904_FLL_OUTDIV_MASK                  0x3F00  /* FLL_OUTDIV - [13:8] */
+#define WM8904_FLL_OUTDIV_SHIFT                      8  /* FLL_OUTDIV - [13:8] */
+#define WM8904_FLL_OUTDIV_WIDTH                      6  /* FLL_OUTDIV - [13:8] */
+#define WM8904_FLL_CTRL_RATE_MASK               0x0070  /* FLL_CTRL_RATE - [6:4] */
+#define WM8904_FLL_CTRL_RATE_SHIFT                   4  /* FLL_CTRL_RATE - [6:4] */
+#define WM8904_FLL_CTRL_RATE_WIDTH                   3  /* FLL_CTRL_RATE - [6:4] */
+#define WM8904_FLL_FRATIO_MASK                  0x0007  /* FLL_FRATIO - [2:0] */
+#define WM8904_FLL_FRATIO_SHIFT                      0  /* FLL_FRATIO - [2:0] */
+#define WM8904_FLL_FRATIO_WIDTH                      3  /* FLL_FRATIO - [2:0] */
+
+/*
+ * R118 (0x76) - FLL Control 3
+ */
+#define WM8904_FLL_K_MASK                       0xFFFF  /* FLL_K - [15:0] */
+#define WM8904_FLL_K_SHIFT                           0  /* FLL_K - [15:0] */
+#define WM8904_FLL_K_WIDTH                          16  /* FLL_K - [15:0] */
+
+/*
+ * R119 (0x77) - FLL Control 4
+ */
+#define WM8904_FLL_N_MASK                       0x7FE0  /* FLL_N - [14:5] */
+#define WM8904_FLL_N_SHIFT                           5  /* FLL_N - [14:5] */
+#define WM8904_FLL_N_WIDTH                          10  /* FLL_N - [14:5] */
+#define WM8904_FLL_GAIN_MASK                    0x000F  /* FLL_GAIN - [3:0] */
+#define WM8904_FLL_GAIN_SHIFT                        0  /* FLL_GAIN - [3:0] */
+#define WM8904_FLL_GAIN_WIDTH                        4  /* FLL_GAIN - [3:0] */
+
+/*
+ * R120 (0x78) - FLL Control 5
+ */
+#define WM8904_FLL_CLK_REF_DIV_MASK             0x0018  /* FLL_CLK_REF_DIV - [4:3] */
+#define WM8904_FLL_CLK_REF_DIV_SHIFT                 3  /* FLL_CLK_REF_DIV - [4:3] */
+#define WM8904_FLL_CLK_REF_DIV_WIDTH                 2  /* FLL_CLK_REF_DIV - [4:3] */
+#define WM8904_FLL_CLK_REF_SRC_MASK             0x0003  /* FLL_CLK_REF_SRC - [1:0] */
+#define WM8904_FLL_CLK_REF_SRC_SHIFT                 0  /* FLL_CLK_REF_SRC - [1:0] */
+#define WM8904_FLL_CLK_REF_SRC_WIDTH                 2  /* FLL_CLK_REF_SRC - [1:0] */
+
+/*
+ * R121 (0x79) - GPIO Control 1
+ */
+#define WM8904_GPIO1_PU                         0x0020  /* GPIO1_PU */
+#define WM8904_GPIO1_PU_MASK                    0x0020  /* GPIO1_PU */
+#define WM8904_GPIO1_PU_SHIFT                        5  /* GPIO1_PU */
+#define WM8904_GPIO1_PU_WIDTH                        1  /* GPIO1_PU */
+#define WM8904_GPIO1_PD                         0x0010  /* GPIO1_PD */
+#define WM8904_GPIO1_PD_MASK                    0x0010  /* GPIO1_PD */
+#define WM8904_GPIO1_PD_SHIFT                        4  /* GPIO1_PD */
+#define WM8904_GPIO1_PD_WIDTH                        1  /* GPIO1_PD */
+#define WM8904_GPIO1_SEL_MASK                   0x000F  /* GPIO1_SEL - [3:0] */
+#define WM8904_GPIO1_SEL_SHIFT                       0  /* GPIO1_SEL - [3:0] */
+#define WM8904_GPIO1_SEL_WIDTH                       4  /* GPIO1_SEL - [3:0] */
+
+/*
+ * R122 (0x7A) - GPIO Control 2
+ */
+#define WM8904_GPIO2_PU                         0x0020  /* GPIO2_PU */
+#define WM8904_GPIO2_PU_MASK                    0x0020  /* GPIO2_PU */
+#define WM8904_GPIO2_PU_SHIFT                        5  /* GPIO2_PU */
+#define WM8904_GPIO2_PU_WIDTH                        1  /* GPIO2_PU */
+#define WM8904_GPIO2_PD                         0x0010  /* GPIO2_PD */
+#define WM8904_GPIO2_PD_MASK                    0x0010  /* GPIO2_PD */
+#define WM8904_GPIO2_PD_SHIFT                        4  /* GPIO2_PD */
+#define WM8904_GPIO2_PD_WIDTH                        1  /* GPIO2_PD */
+#define WM8904_GPIO2_SEL_MASK                   0x000F  /* GPIO2_SEL - [3:0] */
+#define WM8904_GPIO2_SEL_SHIFT                       0  /* GPIO2_SEL - [3:0] */
+#define WM8904_GPIO2_SEL_WIDTH                       4  /* GPIO2_SEL - [3:0] */
+
+/*
+ * R123 (0x7B) - GPIO Control 3
+ */
+#define WM8904_GPIO3_PU                         0x0020  /* GPIO3_PU */
+#define WM8904_GPIO3_PU_MASK                    0x0020  /* GPIO3_PU */
+#define WM8904_GPIO3_PU_SHIFT                        5  /* GPIO3_PU */
+#define WM8904_GPIO3_PU_WIDTH                        1  /* GPIO3_PU */
+#define WM8904_GPIO3_PD                         0x0010  /* GPIO3_PD */
+#define WM8904_GPIO3_PD_MASK                    0x0010  /* GPIO3_PD */
+#define WM8904_GPIO3_PD_SHIFT                        4  /* GPIO3_PD */
+#define WM8904_GPIO3_PD_WIDTH                        1  /* GPIO3_PD */
+#define WM8904_GPIO3_SEL_MASK                   0x000F  /* GPIO3_SEL - [3:0] */
+#define WM8904_GPIO3_SEL_SHIFT                       0  /* GPIO3_SEL - [3:0] */
+#define WM8904_GPIO3_SEL_WIDTH                       4  /* GPIO3_SEL - [3:0] */
+
+/*
+ * R124 (0x7C) - GPIO Control 4
+ */
+#define WM8904_GPI7_ENA                         0x0200  /* GPI7_ENA */
+#define WM8904_GPI7_ENA_MASK                    0x0200  /* GPI7_ENA */
+#define WM8904_GPI7_ENA_SHIFT                        9  /* GPI7_ENA */
+#define WM8904_GPI7_ENA_WIDTH                        1  /* GPI7_ENA */
+#define WM8904_GPI8_ENA                         0x0100  /* GPI8_ENA */
+#define WM8904_GPI8_ENA_MASK                    0x0100  /* GPI8_ENA */
+#define WM8904_GPI8_ENA_SHIFT                        8  /* GPI8_ENA */
+#define WM8904_GPI8_ENA_WIDTH                        1  /* GPI8_ENA */
+#define WM8904_GPIO_BCLK_MODE_ENA               0x0080  /* GPIO_BCLK_MODE_ENA */
+#define WM8904_GPIO_BCLK_MODE_ENA_MASK          0x0080  /* GPIO_BCLK_MODE_ENA */
+#define WM8904_GPIO_BCLK_MODE_ENA_SHIFT              7  /* GPIO_BCLK_MODE_ENA */
+#define WM8904_GPIO_BCLK_MODE_ENA_WIDTH              1  /* GPIO_BCLK_MODE_ENA */
+#define WM8904_GPIO_BCLK_SEL_MASK               0x000F  /* GPIO_BCLK_SEL - [3:0] */
+#define WM8904_GPIO_BCLK_SEL_SHIFT                   0  /* GPIO_BCLK_SEL - [3:0] */
+#define WM8904_GPIO_BCLK_SEL_WIDTH                   4  /* GPIO_BCLK_SEL - [3:0] */
+
+/*
+ * R126 (0x7E) - Digital Pulls
+ */
+#define WM8904_MCLK_PU                          0x0080  /* MCLK_PU */
+#define WM8904_MCLK_PU_MASK                     0x0080  /* MCLK_PU */
+#define WM8904_MCLK_PU_SHIFT                         7  /* MCLK_PU */
+#define WM8904_MCLK_PU_WIDTH                         1  /* MCLK_PU */
+#define WM8904_MCLK_PD                          0x0040  /* MCLK_PD */
+#define WM8904_MCLK_PD_MASK                     0x0040  /* MCLK_PD */
+#define WM8904_MCLK_PD_SHIFT                         6  /* MCLK_PD */
+#define WM8904_MCLK_PD_WIDTH                         1  /* MCLK_PD */
+#define WM8904_DACDAT_PU                        0x0020  /* DACDAT_PU */
+#define WM8904_DACDAT_PU_MASK                   0x0020  /* DACDAT_PU */
+#define WM8904_DACDAT_PU_SHIFT                       5  /* DACDAT_PU */
+#define WM8904_DACDAT_PU_WIDTH                       1  /* DACDAT_PU */
+#define WM8904_DACDAT_PD                        0x0010  /* DACDAT_PD */
+#define WM8904_DACDAT_PD_MASK                   0x0010  /* DACDAT_PD */
+#define WM8904_DACDAT_PD_SHIFT                       4  /* DACDAT_PD */
+#define WM8904_DACDAT_PD_WIDTH                       1  /* DACDAT_PD */
+#define WM8904_LRCLK_PU                         0x0008  /* LRCLK_PU */
+#define WM8904_LRCLK_PU_MASK                    0x0008  /* LRCLK_PU */
+#define WM8904_LRCLK_PU_SHIFT                        3  /* LRCLK_PU */
+#define WM8904_LRCLK_PU_WIDTH                        1  /* LRCLK_PU */
+#define WM8904_LRCLK_PD                         0x0004  /* LRCLK_PD */
+#define WM8904_LRCLK_PD_MASK                    0x0004  /* LRCLK_PD */
+#define WM8904_LRCLK_PD_SHIFT                        2  /* LRCLK_PD */
+#define WM8904_LRCLK_PD_WIDTH                        1  /* LRCLK_PD */
+#define WM8904_BCLK_PU                          0x0002  /* BCLK_PU */
+#define WM8904_BCLK_PU_MASK                     0x0002  /* BCLK_PU */
+#define WM8904_BCLK_PU_SHIFT                         1  /* BCLK_PU */
+#define WM8904_BCLK_PU_WIDTH                         1  /* BCLK_PU */
+#define WM8904_BCLK_PD                          0x0001  /* BCLK_PD */
+#define WM8904_BCLK_PD_MASK                     0x0001  /* BCLK_PD */
+#define WM8904_BCLK_PD_SHIFT                         0  /* BCLK_PD */
+#define WM8904_BCLK_PD_WIDTH                         1  /* BCLK_PD */
+
+/*
+ * R127 (0x7F) - Interrupt Status
+ */
+#define WM8904_IRQ                              0x0400  /* IRQ */
+#define WM8904_IRQ_MASK                         0x0400  /* IRQ */
+#define WM8904_IRQ_SHIFT                            10  /* IRQ */
+#define WM8904_IRQ_WIDTH                             1  /* IRQ */
+#define WM8904_GPIO_BCLK_EINT                   0x0200  /* GPIO_BCLK_EINT */
+#define WM8904_GPIO_BCLK_EINT_MASK              0x0200  /* GPIO_BCLK_EINT */
+#define WM8904_GPIO_BCLK_EINT_SHIFT                  9  /* GPIO_BCLK_EINT */
+#define WM8904_GPIO_BCLK_EINT_WIDTH                  1  /* GPIO_BCLK_EINT */
+#define WM8904_WSEQ_EINT                        0x0100  /* WSEQ_EINT */
+#define WM8904_WSEQ_EINT_MASK                   0x0100  /* WSEQ_EINT */
+#define WM8904_WSEQ_EINT_SHIFT                       8  /* WSEQ_EINT */
+#define WM8904_WSEQ_EINT_WIDTH                       1  /* WSEQ_EINT */
+#define WM8904_GPIO3_EINT                       0x0080  /* GPIO3_EINT */
+#define WM8904_GPIO3_EINT_MASK                  0x0080  /* GPIO3_EINT */
+#define WM8904_GPIO3_EINT_SHIFT                      7  /* GPIO3_EINT */
+#define WM8904_GPIO3_EINT_WIDTH                      1  /* GPIO3_EINT */
+#define WM8904_GPIO2_EINT                       0x0040  /* GPIO2_EINT */
+#define WM8904_GPIO2_EINT_MASK                  0x0040  /* GPIO2_EINT */
+#define WM8904_GPIO2_EINT_SHIFT                      6  /* GPIO2_EINT */
+#define WM8904_GPIO2_EINT_WIDTH                      1  /* GPIO2_EINT */
+#define WM8904_GPIO1_EINT                       0x0020  /* GPIO1_EINT */
+#define WM8904_GPIO1_EINT_MASK                  0x0020  /* GPIO1_EINT */
+#define WM8904_GPIO1_EINT_SHIFT                      5  /* GPIO1_EINT */
+#define WM8904_GPIO1_EINT_WIDTH                      1  /* GPIO1_EINT */
+#define WM8904_GPI8_EINT                        0x0010  /* GPI8_EINT */
+#define WM8904_GPI8_EINT_MASK                   0x0010  /* GPI8_EINT */
+#define WM8904_GPI8_EINT_SHIFT                       4  /* GPI8_EINT */
+#define WM8904_GPI8_EINT_WIDTH                       1  /* GPI8_EINT */
+#define WM8904_GPI7_EINT                        0x0008  /* GPI7_EINT */
+#define WM8904_GPI7_EINT_MASK                   0x0008  /* GPI7_EINT */
+#define WM8904_GPI7_EINT_SHIFT                       3  /* GPI7_EINT */
+#define WM8904_GPI7_EINT_WIDTH                       1  /* GPI7_EINT */
+#define WM8904_FLL_LOCK_EINT                    0x0004  /* FLL_LOCK_EINT */
+#define WM8904_FLL_LOCK_EINT_MASK               0x0004  /* FLL_LOCK_EINT */
+#define WM8904_FLL_LOCK_EINT_SHIFT                   2  /* FLL_LOCK_EINT */
+#define WM8904_FLL_LOCK_EINT_WIDTH                   1  /* FLL_LOCK_EINT */
+#define WM8904_MIC_SHRT_EINT                    0x0002  /* MIC_SHRT_EINT */
+#define WM8904_MIC_SHRT_EINT_MASK               0x0002  /* MIC_SHRT_EINT */
+#define WM8904_MIC_SHRT_EINT_SHIFT                   1  /* MIC_SHRT_EINT */
+#define WM8904_MIC_SHRT_EINT_WIDTH                   1  /* MIC_SHRT_EINT */
+#define WM8904_MIC_DET_EINT                     0x0001  /* MIC_DET_EINT */
+#define WM8904_MIC_DET_EINT_MASK                0x0001  /* MIC_DET_EINT */
+#define WM8904_MIC_DET_EINT_SHIFT                    0  /* MIC_DET_EINT */
+#define WM8904_MIC_DET_EINT_WIDTH                    1  /* MIC_DET_EINT */
+
+/*
+ * R128 (0x80) - Interrupt Status Mask
+ */
+#define WM8904_IM_GPIO_BCLK_EINT                0x0200  /* IM_GPIO_BCLK_EINT */
+#define WM8904_IM_GPIO_BCLK_EINT_MASK           0x0200  /* IM_GPIO_BCLK_EINT */
+#define WM8904_IM_GPIO_BCLK_EINT_SHIFT               9  /* IM_GPIO_BCLK_EINT */
+#define WM8904_IM_GPIO_BCLK_EINT_WIDTH               1  /* IM_GPIO_BCLK_EINT */
+#define WM8904_IM_WSEQ_EINT                     0x0100  /* IM_WSEQ_EINT */
+#define WM8904_IM_WSEQ_EINT_MASK                0x0100  /* IM_WSEQ_EINT */
+#define WM8904_IM_WSEQ_EINT_SHIFT                    8  /* IM_WSEQ_EINT */
+#define WM8904_IM_WSEQ_EINT_WIDTH                    1  /* IM_WSEQ_EINT */
+#define WM8904_IM_GPIO3_EINT                    0x0080  /* IM_GPIO3_EINT */
+#define WM8904_IM_GPIO3_EINT_MASK               0x0080  /* IM_GPIO3_EINT */
+#define WM8904_IM_GPIO3_EINT_SHIFT                   7  /* IM_GPIO3_EINT */
+#define WM8904_IM_GPIO3_EINT_WIDTH                   1  /* IM_GPIO3_EINT */
+#define WM8904_IM_GPIO2_EINT                    0x0040  /* IM_GPIO2_EINT */
+#define WM8904_IM_GPIO2_EINT_MASK               0x0040  /* IM_GPIO2_EINT */
+#define WM8904_IM_GPIO2_EINT_SHIFT                   6  /* IM_GPIO2_EINT */
+#define WM8904_IM_GPIO2_EINT_WIDTH                   1  /* IM_GPIO2_EINT */
+#define WM8904_IM_GPIO1_EINT                    0x0020  /* IM_GPIO1_EINT */
+#define WM8904_IM_GPIO1_EINT_MASK               0x0020  /* IM_GPIO1_EINT */
+#define WM8904_IM_GPIO1_EINT_SHIFT                   5  /* IM_GPIO1_EINT */
+#define WM8904_IM_GPIO1_EINT_WIDTH                   1  /* IM_GPIO1_EINT */
+#define WM8904_IM_GPI8_EINT                     0x0010  /* IM_GPI8_EINT */
+#define WM8904_IM_GPI8_EINT_MASK                0x0010  /* IM_GPI8_EINT */
+#define WM8904_IM_GPI8_EINT_SHIFT                    4  /* IM_GPI8_EINT */
+#define WM8904_IM_GPI8_EINT_WIDTH                    1  /* IM_GPI8_EINT */
+#define WM8904_IM_GPI7_EINT                     0x0008  /* IM_GPI7_EINT */
+#define WM8904_IM_GPI7_EINT_MASK                0x0008  /* IM_GPI7_EINT */
+#define WM8904_IM_GPI7_EINT_SHIFT                    3  /* IM_GPI7_EINT */
+#define WM8904_IM_GPI7_EINT_WIDTH                    1  /* IM_GPI7_EINT */
+#define WM8904_IM_FLL_LOCK_EINT                 0x0004  /* IM_FLL_LOCK_EINT */
+#define WM8904_IM_FLL_LOCK_EINT_MASK            0x0004  /* IM_FLL_LOCK_EINT */
+#define WM8904_IM_FLL_LOCK_EINT_SHIFT                2  /* IM_FLL_LOCK_EINT */
+#define WM8904_IM_FLL_LOCK_EINT_WIDTH                1  /* IM_FLL_LOCK_EINT */
+#define WM8904_IM_MIC_SHRT_EINT                 0x0002  /* IM_MIC_SHRT_EINT */
+#define WM8904_IM_MIC_SHRT_EINT_MASK            0x0002  /* IM_MIC_SHRT_EINT */
+#define WM8904_IM_MIC_SHRT_EINT_SHIFT                1  /* IM_MIC_SHRT_EINT */
+#define WM8904_IM_MIC_SHRT_EINT_WIDTH                1  /* IM_MIC_SHRT_EINT */
+#define WM8904_IM_MIC_DET_EINT                  0x0001  /* IM_MIC_DET_EINT */
+#define WM8904_IM_MIC_DET_EINT_MASK             0x0001  /* IM_MIC_DET_EINT */
+#define WM8904_IM_MIC_DET_EINT_SHIFT                 0  /* IM_MIC_DET_EINT */
+#define WM8904_IM_MIC_DET_EINT_WIDTH                 1  /* IM_MIC_DET_EINT */
+
+/*
+ * R129 (0x81) - Interrupt Polarity
+ */
+#define WM8904_GPIO_BCLK_EINT_POL               0x0200  /* GPIO_BCLK_EINT_POL */
+#define WM8904_GPIO_BCLK_EINT_POL_MASK          0x0200  /* GPIO_BCLK_EINT_POL */
+#define WM8904_GPIO_BCLK_EINT_POL_SHIFT              9  /* GPIO_BCLK_EINT_POL */
+#define WM8904_GPIO_BCLK_EINT_POL_WIDTH              1  /* GPIO_BCLK_EINT_POL */
+#define WM8904_WSEQ_EINT_POL                    0x0100  /* WSEQ_EINT_POL */
+#define WM8904_WSEQ_EINT_POL_MASK               0x0100  /* WSEQ_EINT_POL */
+#define WM8904_WSEQ_EINT_POL_SHIFT                   8  /* WSEQ_EINT_POL */
+#define WM8904_WSEQ_EINT_POL_WIDTH                   1  /* WSEQ_EINT_POL */
+#define WM8904_GPIO3_EINT_POL                   0x0080  /* GPIO3_EINT_POL */
+#define WM8904_GPIO3_EINT_POL_MASK              0x0080  /* GPIO3_EINT_POL */
+#define WM8904_GPIO3_EINT_POL_SHIFT                  7  /* GPIO3_EINT_POL */
+#define WM8904_GPIO3_EINT_POL_WIDTH                  1  /* GPIO3_EINT_POL */
+#define WM8904_GPIO2_EINT_POL                   0x0040  /* GPIO2_EINT_POL */
+#define WM8904_GPIO2_EINT_POL_MASK              0x0040  /* GPIO2_EINT_POL */
+#define WM8904_GPIO2_EINT_POL_SHIFT                  6  /* GPIO2_EINT_POL */
+#define WM8904_GPIO2_EINT_POL_WIDTH                  1  /* GPIO2_EINT_POL */
+#define WM8904_GPIO1_EINT_POL                   0x0020  /* GPIO1_EINT_POL */
+#define WM8904_GPIO1_EINT_POL_MASK              0x0020  /* GPIO1_EINT_POL */
+#define WM8904_GPIO1_EINT_POL_SHIFT                  5  /* GPIO1_EINT_POL */
+#define WM8904_GPIO1_EINT_POL_WIDTH                  1  /* GPIO1_EINT_POL */
+#define WM8904_GPI8_EINT_POL                    0x0010  /* GPI8_EINT_POL */
+#define WM8904_GPI8_EINT_POL_MASK               0x0010  /* GPI8_EINT_POL */
+#define WM8904_GPI8_EINT_POL_SHIFT                   4  /* GPI8_EINT_POL */
+#define WM8904_GPI8_EINT_POL_WIDTH                   1  /* GPI8_EINT_POL */
+#define WM8904_GPI7_EINT_POL                    0x0008  /* GPI7_EINT_POL */
+#define WM8904_GPI7_EINT_POL_MASK               0x0008  /* GPI7_EINT_POL */
+#define WM8904_GPI7_EINT_POL_SHIFT                   3  /* GPI7_EINT_POL */
+#define WM8904_GPI7_EINT_POL_WIDTH                   1  /* GPI7_EINT_POL */
+#define WM8904_FLL_LOCK_EINT_POL                0x0004  /* FLL_LOCK_EINT_POL */
+#define WM8904_FLL_LOCK_EINT_POL_MASK           0x0004  /* FLL_LOCK_EINT_POL */
+#define WM8904_FLL_LOCK_EINT_POL_SHIFT               2  /* FLL_LOCK_EINT_POL */
+#define WM8904_FLL_LOCK_EINT_POL_WIDTH               1  /* FLL_LOCK_EINT_POL */
+#define WM8904_MIC_SHRT_EINT_POL                0x0002  /* MIC_SHRT_EINT_POL */
+#define WM8904_MIC_SHRT_EINT_POL_MASK           0x0002  /* MIC_SHRT_EINT_POL */
+#define WM8904_MIC_SHRT_EINT_POL_SHIFT               1  /* MIC_SHRT_EINT_POL */
+#define WM8904_MIC_SHRT_EINT_POL_WIDTH               1  /* MIC_SHRT_EINT_POL */
+#define WM8904_MIC_DET_EINT_POL                 0x0001  /* MIC_DET_EINT_POL */
+#define WM8904_MIC_DET_EINT_POL_MASK            0x0001  /* MIC_DET_EINT_POL */
+#define WM8904_MIC_DET_EINT_POL_SHIFT                0  /* MIC_DET_EINT_POL */
+#define WM8904_MIC_DET_EINT_POL_WIDTH                1  /* MIC_DET_EINT_POL */
+
+/*
+ * R130 (0x82) - Interrupt Debounce
+ */
+#define WM8904_GPIO_BCLK_EINT_DB                0x0200  /* GPIO_BCLK_EINT_DB */
+#define WM8904_GPIO_BCLK_EINT_DB_MASK           0x0200  /* GPIO_BCLK_EINT_DB */
+#define WM8904_GPIO_BCLK_EINT_DB_SHIFT               9  /* GPIO_BCLK_EINT_DB */
+#define WM8904_GPIO_BCLK_EINT_DB_WIDTH               1  /* GPIO_BCLK_EINT_DB */
+#define WM8904_WSEQ_EINT_DB                     0x0100  /* WSEQ_EINT_DB */
+#define WM8904_WSEQ_EINT_DB_MASK                0x0100  /* WSEQ_EINT_DB */
+#define WM8904_WSEQ_EINT_DB_SHIFT                    8  /* WSEQ_EINT_DB */
+#define WM8904_WSEQ_EINT_DB_WIDTH                    1  /* WSEQ_EINT_DB */
+#define WM8904_GPIO3_EINT_DB                    0x0080  /* GPIO3_EINT_DB */
+#define WM8904_GPIO3_EINT_DB_MASK               0x0080  /* GPIO3_EINT_DB */
+#define WM8904_GPIO3_EINT_DB_SHIFT                   7  /* GPIO3_EINT_DB */
+#define WM8904_GPIO3_EINT_DB_WIDTH                   1  /* GPIO3_EINT_DB */
+#define WM8904_GPIO2_EINT_DB                    0x0040  /* GPIO2_EINT_DB */
+#define WM8904_GPIO2_EINT_DB_MASK               0x0040  /* GPIO2_EINT_DB */
+#define WM8904_GPIO2_EINT_DB_SHIFT                   6  /* GPIO2_EINT_DB */
+#define WM8904_GPIO2_EINT_DB_WIDTH                   1  /* GPIO2_EINT_DB */
+#define WM8904_GPIO1_EINT_DB                    0x0020  /* GPIO1_EINT_DB */
+#define WM8904_GPIO1_EINT_DB_MASK               0x0020  /* GPIO1_EINT_DB */
+#define WM8904_GPIO1_EINT_DB_SHIFT                   5  /* GPIO1_EINT_DB */
+#define WM8904_GPIO1_EINT_DB_WIDTH                   1  /* GPIO1_EINT_DB */
+#define WM8904_GPI8_EINT_DB                     0x0010  /* GPI8_EINT_DB */
+#define WM8904_GPI8_EINT_DB_MASK                0x0010  /* GPI8_EINT_DB */
+#define WM8904_GPI8_EINT_DB_SHIFT                    4  /* GPI8_EINT_DB */
+#define WM8904_GPI8_EINT_DB_WIDTH                    1  /* GPI8_EINT_DB */
+#define WM8904_GPI7_EINT_DB                     0x0008  /* GPI7_EINT_DB */
+#define WM8904_GPI7_EINT_DB_MASK                0x0008  /* GPI7_EINT_DB */
+#define WM8904_GPI7_EINT_DB_SHIFT                    3  /* GPI7_EINT_DB */
+#define WM8904_GPI7_EINT_DB_WIDTH                    1  /* GPI7_EINT_DB */
+#define WM8904_FLL_LOCK_EINT_DB                 0x0004  /* FLL_LOCK_EINT_DB */
+#define WM8904_FLL_LOCK_EINT_DB_MASK            0x0004  /* FLL_LOCK_EINT_DB */
+#define WM8904_FLL_LOCK_EINT_DB_SHIFT                2  /* FLL_LOCK_EINT_DB */
+#define WM8904_FLL_LOCK_EINT_DB_WIDTH                1  /* FLL_LOCK_EINT_DB */
+#define WM8904_MIC_SHRT_EINT_DB                 0x0002  /* MIC_SHRT_EINT_DB */
+#define WM8904_MIC_SHRT_EINT_DB_MASK            0x0002  /* MIC_SHRT_EINT_DB */
+#define WM8904_MIC_SHRT_EINT_DB_SHIFT                1  /* MIC_SHRT_EINT_DB */
+#define WM8904_MIC_SHRT_EINT_DB_WIDTH                1  /* MIC_SHRT_EINT_DB */
+#define WM8904_MIC_DET_EINT_DB                  0x0001  /* MIC_DET_EINT_DB */
+#define WM8904_MIC_DET_EINT_DB_MASK             0x0001  /* MIC_DET_EINT_DB */
+#define WM8904_MIC_DET_EINT_DB_SHIFT                 0  /* MIC_DET_EINT_DB */
+#define WM8904_MIC_DET_EINT_DB_WIDTH                 1  /* MIC_DET_EINT_DB */
+
+/*
+ * R134 (0x86) - EQ1
+ */
+#define WM8904_EQ_ENA                           0x0001  /* EQ_ENA */
+#define WM8904_EQ_ENA_MASK                      0x0001  /* EQ_ENA */
+#define WM8904_EQ_ENA_SHIFT                          0  /* EQ_ENA */
+#define WM8904_EQ_ENA_WIDTH                          1  /* EQ_ENA */
+
+/*
+ * R135 (0x87) - EQ2
+ */
+#define WM8904_EQ_B1_GAIN_MASK                  0x001F  /* EQ_B1_GAIN - [4:0] */
+#define WM8904_EQ_B1_GAIN_SHIFT                      0  /* EQ_B1_GAIN - [4:0] */
+#define WM8904_EQ_B1_GAIN_WIDTH                      5  /* EQ_B1_GAIN - [4:0] */
+
+/*
+ * R136 (0x88) - EQ3
+ */
+#define WM8904_EQ_B2_GAIN_MASK                  0x001F  /* EQ_B2_GAIN - [4:0] */
+#define WM8904_EQ_B2_GAIN_SHIFT                      0  /* EQ_B2_GAIN - [4:0] */
+#define WM8904_EQ_B2_GAIN_WIDTH                      5  /* EQ_B2_GAIN - [4:0] */
+
+/*
+ * R137 (0x89) - EQ4
+ */
+#define WM8904_EQ_B3_GAIN_MASK                  0x001F  /* EQ_B3_GAIN - [4:0] */
+#define WM8904_EQ_B3_GAIN_SHIFT                      0  /* EQ_B3_GAIN - [4:0] */
+#define WM8904_EQ_B3_GAIN_WIDTH                      5  /* EQ_B3_GAIN - [4:0] */
+
+/*
+ * R138 (0x8A) - EQ5
+ */
+#define WM8904_EQ_B4_GAIN_MASK                  0x001F  /* EQ_B4_GAIN - [4:0] */
+#define WM8904_EQ_B4_GAIN_SHIFT                      0  /* EQ_B4_GAIN - [4:0] */
+#define WM8904_EQ_B4_GAIN_WIDTH                      5  /* EQ_B4_GAIN - [4:0] */
+
+/*
+ * R139 (0x8B) - EQ6
+ */
+#define WM8904_EQ_B5_GAIN_MASK                  0x001F  /* EQ_B5_GAIN - [4:0] */
+#define WM8904_EQ_B5_GAIN_SHIFT                      0  /* EQ_B5_GAIN - [4:0] */
+#define WM8904_EQ_B5_GAIN_WIDTH                      5  /* EQ_B5_GAIN - [4:0] */
+
+/*
+ * R140 (0x8C) - EQ7
+ */
+#define WM8904_EQ_B1_A_MASK                     0xFFFF  /* EQ_B1_A - [15:0] */
+#define WM8904_EQ_B1_A_SHIFT                         0  /* EQ_B1_A - [15:0] */
+#define WM8904_EQ_B1_A_WIDTH                        16  /* EQ_B1_A - [15:0] */
+
+/*
+ * R141 (0x8D) - EQ8
+ */
+#define WM8904_EQ_B1_B_MASK                     0xFFFF  /* EQ_B1_B - [15:0] */
+#define WM8904_EQ_B1_B_SHIFT                         0  /* EQ_B1_B - [15:0] */
+#define WM8904_EQ_B1_B_WIDTH                        16  /* EQ_B1_B - [15:0] */
+
+/*
+ * R142 (0x8E) - EQ9
+ */
+#define WM8904_EQ_B1_PG_MASK                    0xFFFF  /* EQ_B1_PG - [15:0] */
+#define WM8904_EQ_B1_PG_SHIFT                        0  /* EQ_B1_PG - [15:0] */
+#define WM8904_EQ_B1_PG_WIDTH                       16  /* EQ_B1_PG - [15:0] */
+
+/*
+ * R143 (0x8F) - EQ10
+ */
+#define WM8904_EQ_B2_A_MASK                     0xFFFF  /* EQ_B2_A - [15:0] */
+#define WM8904_EQ_B2_A_SHIFT                         0  /* EQ_B2_A - [15:0] */
+#define WM8904_EQ_B2_A_WIDTH                        16  /* EQ_B2_A - [15:0] */
+
+/*
+ * R144 (0x90) - EQ11
+ */
+#define WM8904_EQ_B2_B_MASK                     0xFFFF  /* EQ_B2_B - [15:0] */
+#define WM8904_EQ_B2_B_SHIFT                         0  /* EQ_B2_B - [15:0] */
+#define WM8904_EQ_B2_B_WIDTH                        16  /* EQ_B2_B - [15:0] */
+
+/*
+ * R145 (0x91) - EQ12
+ */
+#define WM8904_EQ_B2_C_MASK                     0xFFFF  /* EQ_B2_C - [15:0] */
+#define WM8904_EQ_B2_C_SHIFT                         0  /* EQ_B2_C - [15:0] */
+#define WM8904_EQ_B2_C_WIDTH                        16  /* EQ_B2_C - [15:0] */
+
+/*
+ * R146 (0x92) - EQ13
+ */
+#define WM8904_EQ_B2_PG_MASK                    0xFFFF  /* EQ_B2_PG - [15:0] */
+#define WM8904_EQ_B2_PG_SHIFT                        0  /* EQ_B2_PG - [15:0] */
+#define WM8904_EQ_B2_PG_WIDTH                       16  /* EQ_B2_PG - [15:0] */
+
+/*
+ * R147 (0x93) - EQ14
+ */
+#define WM8904_EQ_B3_A_MASK                     0xFFFF  /* EQ_B3_A - [15:0] */
+#define WM8904_EQ_B3_A_SHIFT                         0  /* EQ_B3_A - [15:0] */
+#define WM8904_EQ_B3_A_WIDTH                        16  /* EQ_B3_A - [15:0] */
+
+/*
+ * R148 (0x94) - EQ15
+ */
+#define WM8904_EQ_B3_B_MASK                     0xFFFF  /* EQ_B3_B - [15:0] */
+#define WM8904_EQ_B3_B_SHIFT                         0  /* EQ_B3_B - [15:0] */
+#define WM8904_EQ_B3_B_WIDTH                        16  /* EQ_B3_B - [15:0] */
+
+/*
+ * R149 (0x95) - EQ16
+ */
+#define WM8904_EQ_B3_C_MASK                     0xFFFF  /* EQ_B3_C - [15:0] */
+#define WM8904_EQ_B3_C_SHIFT                         0  /* EQ_B3_C - [15:0] */
+#define WM8904_EQ_B3_C_WIDTH                        16  /* EQ_B3_C - [15:0] */
+
+/*
+ * R150 (0x96) - EQ17
+ */
+#define WM8904_EQ_B3_PG_MASK                    0xFFFF  /* EQ_B3_PG - [15:0] */
+#define WM8904_EQ_B3_PG_SHIFT                        0  /* EQ_B3_PG - [15:0] */
+#define WM8904_EQ_B3_PG_WIDTH                       16  /* EQ_B3_PG - [15:0] */
+
+/*
+ * R151 (0x97) - EQ18
+ */
+#define WM8904_EQ_B4_A_MASK                     0xFFFF  /* EQ_B4_A - [15:0] */
+#define WM8904_EQ_B4_A_SHIFT                         0  /* EQ_B4_A - [15:0] */
+#define WM8904_EQ_B4_A_WIDTH                        16  /* EQ_B4_A - [15:0] */
+
+/*
+ * R152 (0x98) - EQ19
+ */
+#define WM8904_EQ_B4_B_MASK                     0xFFFF  /* EQ_B4_B - [15:0] */
+#define WM8904_EQ_B4_B_SHIFT                         0  /* EQ_B4_B - [15:0] */
+#define WM8904_EQ_B4_B_WIDTH                        16  /* EQ_B4_B - [15:0] */
+
+/*
+ * R153 (0x99) - EQ20
+ */
+#define WM8904_EQ_B4_C_MASK                     0xFFFF  /* EQ_B4_C - [15:0] */
+#define WM8904_EQ_B4_C_SHIFT                         0  /* EQ_B4_C - [15:0] */
+#define WM8904_EQ_B4_C_WIDTH                        16  /* EQ_B4_C - [15:0] */
+
+/*
+ * R154 (0x9A) - EQ21
+ */
+#define WM8904_EQ_B4_PG_MASK                    0xFFFF  /* EQ_B4_PG - [15:0] */
+#define WM8904_EQ_B4_PG_SHIFT                        0  /* EQ_B4_PG - [15:0] */
+#define WM8904_EQ_B4_PG_WIDTH                       16  /* EQ_B4_PG - [15:0] */
+
+/*
+ * R155 (0x9B) - EQ22
+ */
+#define WM8904_EQ_B5_A_MASK                     0xFFFF  /* EQ_B5_A - [15:0] */
+#define WM8904_EQ_B5_A_SHIFT                         0  /* EQ_B5_A - [15:0] */
+#define WM8904_EQ_B5_A_WIDTH                        16  /* EQ_B5_A - [15:0] */
+
+/*
+ * R156 (0x9C) - EQ23
+ */
+#define WM8904_EQ_B5_B_MASK                     0xFFFF  /* EQ_B5_B - [15:0] */
+#define WM8904_EQ_B5_B_SHIFT                         0  /* EQ_B5_B - [15:0] */
+#define WM8904_EQ_B5_B_WIDTH                        16  /* EQ_B5_B - [15:0] */
+
+/*
+ * R157 (0x9D) - EQ24
+ */
+#define WM8904_EQ_B5_PG_MASK                    0xFFFF  /* EQ_B5_PG - [15:0] */
+#define WM8904_EQ_B5_PG_SHIFT                        0  /* EQ_B5_PG - [15:0] */
+#define WM8904_EQ_B5_PG_WIDTH                       16  /* EQ_B5_PG - [15:0] */
+
+/*
+ * R161 (0xA1) - Control Interface Test 1
+ */
+#define WM8904_USER_KEY                         0x0002  /* USER_KEY */
+#define WM8904_USER_KEY_MASK                    0x0002  /* USER_KEY */
+#define WM8904_USER_KEY_SHIFT                        1  /* USER_KEY */
+#define WM8904_USER_KEY_WIDTH                        1  /* USER_KEY */
+
+/*
+ * R204 (0xCC) - Analogue Output Bias 0
+ */
+#define WM8904_PGA_BIAS_MASK                    0x0070  /* PGA_BIAS - [6:4] */
+#define WM8904_PGA_BIAS_SHIFT                        4  /* PGA_BIAS - [6:4] */
+#define WM8904_PGA_BIAS_WIDTH                        3  /* PGA_BIAS - [6:4] */
+
+/*
+ * R247 (0xF7) - FLL NCO Test 0
+ */
+#define WM8904_FLL_FRC_NCO                      0x0001  /* FLL_FRC_NCO */
+#define WM8904_FLL_FRC_NCO_MASK                 0x0001  /* FLL_FRC_NCO */
+#define WM8904_FLL_FRC_NCO_SHIFT                     0  /* FLL_FRC_NCO */
+#define WM8904_FLL_FRC_NCO_WIDTH                     1  /* FLL_FRC_NCO */
+
+/*
+ * R248 (0xF8) - FLL NCO Test 1
+ */
+#define WM8904_FLL_FRC_NCO_VAL_MASK             0x003F  /* FLL_FRC_NCO_VAL - [5:0] */
+#define WM8904_FLL_FRC_NCO_VAL_SHIFT                 0  /* FLL_FRC_NCO_VAL - [5:0] */
+#define WM8904_FLL_FRC_NCO_VAL_WIDTH                 6  /* FLL_FRC_NCO_VAL - [5:0] */
+
+#endif
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c
new file mode 100644 (file)
index 0000000..615dab2
--- /dev/null
@@ -0,0 +1,1151 @@
+/*
+ * wm8955.c  --  WM8955 ALSA SoC Audio driver
+ *
+ * Copyright 2009 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/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.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 <sound/wm8955.h>
+
+#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",
+       "DBVDD",
+       "HPVDD",
+       "AVDD",
+};
+
+/* codec private data */
+struct wm8955_priv {
+       struct snd_soc_codec codec;
+       u16 reg_cache[WM8955_MAX_REGISTER + 1];
+
+       unsigned int mclk_rate;
+
+       int deemph;
+       int fs;
+
+       struct regulator_bulk_data supplies[WM8955_NUM_SUPPLIES];
+
+       struct wm8955_pdata *pdata;
+};
+
+static const u16 wm8955_reg[WM8955_MAX_REGISTER + 1] = {
+       0x0000,     /* R0 */
+       0x0000,     /* R1 */
+       0x0079,     /* R2  - LOUT1 volume */
+       0x0079,     /* R3  - ROUT1 volume */
+       0x0000,     /* R4 */
+       0x0008,     /* R5  - DAC Control */
+       0x0000,     /* R6 */
+       0x000A,     /* R7  - Audio Interface */
+       0x0000,     /* R8  - Sample Rate */
+       0x0000,     /* R9 */
+       0x00FF,     /* R10 - Left DAC volume */
+       0x00FF,     /* R11 - Right DAC volume */
+       0x000F,     /* R12 - Bass control */
+       0x000F,     /* R13 - Treble control */
+       0x0000,     /* R14 */
+       0x0000,     /* R15 - Reset */
+       0x0000,     /* R16 */
+       0x0000,     /* R17 */
+       0x0000,     /* R18 */
+       0x0000,     /* R19 */
+       0x0000,     /* R20 */
+       0x0000,     /* R21 */
+       0x0000,     /* R22 */
+       0x00C1,     /* R23 - Additional control (1) */
+       0x0000,     /* R24 - Additional control (2) */
+       0x0000,     /* R25 - Power Management (1) */
+       0x0000,     /* R26 - Power Management (2) */
+       0x0000,     /* R27 - Additional Control (3) */
+       0x0000,     /* R28 */
+       0x0000,     /* R29 */
+       0x0000,     /* R30 */
+       0x0000,     /* R31 */
+       0x0000,     /* R32 */
+       0x0000,     /* R33 */
+       0x0050,     /* R34 - Left out Mix (1) */
+       0x0050,     /* R35 - Left out Mix (2) */
+       0x0050,     /* R36 - Right out Mix (1) */
+       0x0050,     /* R37 - Right Out Mix (2) */
+       0x0050,     /* R38 - Mono out Mix (1) */
+       0x0050,     /* R39 - Mono out Mix (2) */
+       0x0079,     /* R40 - LOUT2 volume */
+       0x0079,     /* R41 - ROUT2 volume */
+       0x0079,     /* R42 - MONOOUT volume */
+       0x0000,     /* R43 - Clocking / PLL */
+       0x0103,     /* R44 - PLL Control 1 */
+       0x0024,     /* R45 - PLL Control 2 */
+       0x01BA,     /* R46 - PLL Control 3 */
+       0x0000,     /* R47 */
+       0x0000,     /* R48 */
+       0x0000,     /* R49 */
+       0x0000,     /* R50 */
+       0x0000,     /* R51 */
+       0x0000,     /* R52 */
+       0x0000,     /* R53 */
+       0x0000,     /* R54 */
+       0x0000,     /* R55 */
+       0x0000,     /* R56 */
+       0x0000,     /* R57 */
+       0x0000,     /* R58 */
+       0x0000,     /* R59 - PLL Control 4 */
+};
+
+static int wm8955_reset(struct snd_soc_codec *codec)
+{
+       return snd_soc_write(codec, WM8955_RESET, 0);
+}
+
+struct pll_factors {
+       int n;
+       int k;
+       int outdiv;
+};
+
+/* The size in bits of the FLL divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_FLL_SIZE ((1 << 22) * 10)
+
+static int wm8995_pll_factors(struct device *dev,
+                             int Fref, int Fout, struct pll_factors *pll)
+{
+       u64 Kpart;
+       unsigned int K, Ndiv, Nmod, target;
+
+       dev_dbg(dev, "Fref=%u Fout=%u\n", Fref, Fout);
+
+       /* The oscilator should run at should be 90-100MHz, and
+        * there's a divide by 4 plus an optional divide by 2 in the
+        * output path to generate the system clock.  The clock table
+        * is sortd so we should always generate a suitable target. */
+       target = Fout * 4;
+       if (target < 90000000) {
+               pll->outdiv = 1;
+               target *= 2;
+       } else {
+               pll->outdiv = 0;
+       }
+
+       WARN_ON(target < 90000000 || target > 100000000);
+
+       dev_dbg(dev, "Fvco=%dHz\n", target);
+
+       /* Now, calculate N.K */
+       Ndiv = target / Fref;
+
+       pll->n = Ndiv;
+       Nmod = target % Fref;
+       dev_dbg(dev, "Nmod=%d\n", Nmod);
+
+       /* Calculate fractional part - scale up so we can round. */
+       Kpart = FIXED_FLL_SIZE * (long long)Nmod;
+
+       do_div(Kpart, Fref);
+
+       K = Kpart & 0xFFFFFFFF;
+
+       if ((K % 10) >= 5)
+               K += 5;
+
+       /* Move down to proper range now rounding is done */
+       pll->k = K / 10;
+
+       dev_dbg(dev, "N=%x K=%x OUTDIV=%x\n", pll->n, pll->k, pll->outdiv);
+
+       return 0;
+}
+
+/* Lookup table specifiying SRATE (table 25 in datasheet); some of the
+ * output frequencies have been rounded to the standard frequencies
+ * they are intended to match where the error is slight. */
+static struct {
+       int mclk;
+       int fs;
+       int usb;
+       int sr;
+} clock_cfgs[] = {
+       { 18432000,  8000, 0,  3, },
+       { 18432000, 12000, 0,  9, },
+       { 18432000, 16000, 0, 11, },
+       { 18432000, 24000, 0, 29, },
+       { 18432000, 32000, 0, 13, },
+       { 18432000, 48000, 0,  1, },
+       { 18432000, 96000, 0, 15, },
+
+       { 16934400,  8018, 0, 19, },
+       { 16934400, 11025, 0, 25, },
+       { 16934400, 22050, 0, 27, },
+       { 16934400, 44100, 0, 17, },
+       { 16934400, 88200, 0, 31, },
+
+       { 12000000,  8000, 1,  2, },
+       { 12000000, 11025, 1, 25, },
+       { 12000000, 12000, 1,  8, },
+       { 12000000, 16000, 1, 10, },
+       { 12000000, 22050, 1, 27, },
+       { 12000000, 24000, 1, 28, },
+       { 12000000, 32000, 1, 12, },
+       { 12000000, 44100, 1, 17, },
+       { 12000000, 48000, 1,  0, },
+       { 12000000, 88200, 1, 31, },
+       { 12000000, 96000, 1, 14, },
+
+       { 12288000,  8000, 0,  2, },
+       { 12288000, 12000, 0,  8, },
+       { 12288000, 16000, 0, 10, },
+       { 12288000, 24000, 0, 28, },
+       { 12288000, 32000, 0, 12, },
+       { 12288000, 48000, 0,  0, },
+       { 12288000, 96000, 0, 14, },
+
+       { 12289600,  8018, 0, 18, },
+       { 12289600, 11025, 0, 24, },
+       { 12289600, 22050, 0, 26, },
+       { 11289600, 44100, 0, 16, },
+       { 11289600, 88200, 0, 31, },
+};
+
+static int wm8955_configure_clocking(struct snd_soc_codec *codec)
+{
+       struct wm8955_priv *wm8955 = codec->private_data;
+       int i, ret, val;
+       int clocking = 0;
+       int srate = 0;
+       int sr = -1;
+       struct pll_factors pll;
+
+       /* If we're not running a sample rate currently just pick one */
+       if (wm8955->fs == 0)
+               wm8955->fs = 8000;
+
+       /* Can we generate an exact output? */
+       for (i = 0; i < ARRAY_SIZE(clock_cfgs); i++) {
+               if (wm8955->fs != clock_cfgs[i].fs)
+                       continue;
+               sr = i;
+
+               if (wm8955->mclk_rate == clock_cfgs[i].mclk)
+                       break;
+       }
+
+       /* We should never get here with an unsupported sample rate */
+       if (sr == -1) {
+               dev_err(codec->dev, "Sample rate %dHz unsupported\n",
+                       wm8955->fs);
+               WARN_ON(sr == -1);
+               return -EINVAL;
+       }
+
+       if (i == ARRAY_SIZE(clock_cfgs)) {
+               /* If we can't generate the right clock from MCLK then
+                * we should configure the PLL to supply us with an
+                * appropriate clock.
+                */
+               clocking |= WM8955_MCLKSEL;
+
+               /* Use the last divider configuration we saw for the
+                * sample rate. */
+               ret = wm8995_pll_factors(codec->dev, wm8955->mclk_rate,
+                                        clock_cfgs[sr].mclk, &pll);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Unable to generate %dHz from %dHz MCLK\n",
+                               wm8955->fs, wm8955->mclk_rate);
+                       return -EINVAL;
+               }
+
+               snd_soc_update_bits(codec, WM8955_PLL_CONTROL_1,
+                                   WM8955_N_MASK | WM8955_K_21_18_MASK,
+                                   (pll.n << WM8955_N_SHIFT) |
+                                   pll.k >> 18);
+               snd_soc_update_bits(codec, WM8955_PLL_CONTROL_2,
+                                   WM8955_K_17_9_MASK,
+                                   (pll.k >> 9) & WM8955_K_17_9_MASK);
+               snd_soc_update_bits(codec, WM8955_PLL_CONTROL_2,
+                                   WM8955_K_8_0_MASK,
+                                   pll.k & WM8955_K_8_0_MASK);
+               if (pll.k)
+                       snd_soc_update_bits(codec, WM8955_PLL_CONTROL_4,
+                                           WM8955_KEN, WM8955_KEN);
+               else
+                       snd_soc_update_bits(codec, WM8955_PLL_CONTROL_4,
+                                           WM8955_KEN, 0);
+
+               if (pll.outdiv)
+                       val = WM8955_PLL_RB | WM8955_PLLOUTDIV2;
+               else
+                       val = WM8955_PLL_RB;
+
+               /* Now start the PLL running */
+               snd_soc_update_bits(codec, WM8955_CLOCKING_PLL,
+                                   WM8955_PLL_RB | WM8955_PLLOUTDIV2, val);
+               snd_soc_update_bits(codec, WM8955_CLOCKING_PLL,
+                                   WM8955_PLLEN, WM8955_PLLEN);
+       }
+
+       srate = clock_cfgs[sr].usb | (clock_cfgs[sr].sr << WM8955_SR_SHIFT);
+
+       snd_soc_update_bits(codec, WM8955_SAMPLE_RATE,
+                           WM8955_USB | WM8955_SR_MASK, srate);
+       snd_soc_update_bits(codec, WM8955_CLOCKING_PLL,
+                           WM8955_MCLKSEL, clocking);
+
+       return 0;
+}
+
+static int wm8955_sysclk(struct snd_soc_dapm_widget *w,
+                        struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       int ret = 0;
+
+       /* Always disable the clocks - if we're doing reconfiguration this
+        * avoids misclocking.
+        */
+       snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1,
+                           WM8955_DIGENB, 0);
+       snd_soc_update_bits(codec, WM8955_CLOCKING_PLL,
+                           WM8955_PLL_RB | WM8955_PLLEN, 0);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMD:
+               break;
+       case SND_SOC_DAPM_PRE_PMU:
+               ret = wm8955_configure_clocking(codec);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static int deemph_settings[] = { 0, 32000, 44100, 48000 };
+
+static int wm8955_set_deemph(struct snd_soc_codec *codec)
+{
+       struct wm8955_priv *wm8955 = codec->private_data;
+       int val, i, best;
+
+       /* If we're using deemphasis select the nearest available sample
+        * rate.
+        */
+       if (wm8955->deemph) {
+               best = 1;
+               for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) {
+                       if (abs(deemph_settings[i] - wm8955->fs) <
+                           abs(deemph_settings[best] - wm8955->fs))
+                               best = i;
+               }
+
+               val = best << WM8955_DEEMPH_SHIFT;
+       } else {
+               val = 0;
+       }
+
+       dev_dbg(codec->dev, "Set deemphasis %d\n", val);
+
+       return snd_soc_update_bits(codec, WM8955_DAC_CONTROL,
+                                  WM8955_DEEMPH_MASK, val);
+}
+
+static int wm8955_get_deemph(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8955_priv *wm8955 = codec->private_data;
+
+       return wm8955->deemph;
+}
+
+static int wm8955_put_deemph(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8955_priv *wm8955 = codec->private_data;
+       int deemph = ucontrol->value.enumerated.item[0];
+
+       if (deemph > 1)
+               return -EINVAL;
+
+       wm8955->deemph = deemph;
+
+       return wm8955_set_deemph(codec);
+}
+
+static const char *bass_mode_text[] = {
+       "Linear", "Adaptive",
+};
+
+static const struct soc_enum bass_mode =
+       SOC_ENUM_SINGLE(WM8955_BASS_CONTROL, 7, 2, bass_mode_text);
+
+static const char *bass_cutoff_text[] = {
+       "Low", "High"
+};
+
+static const struct soc_enum bass_cutoff =
+       SOC_ENUM_SINGLE(WM8955_BASS_CONTROL, 6, 2, bass_cutoff_text);
+
+static const char *treble_cutoff_text[] = {
+       "High", "Low"
+};
+
+static const struct soc_enum treble_cutoff =
+       SOC_ENUM_SINGLE(WM8955_TREBLE_CONTROL, 6, 2, treble_cutoff_text);
+
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(atten_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(mono_tlv, -2100, 300, 0);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
+static const DECLARE_TLV_DB_SCALE(treble_tlv, -1200, 150, 1);
+
+static const struct snd_kcontrol_new wm8955_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8955_LEFT_DAC_VOLUME,
+                WM8955_RIGHT_DAC_VOLUME, 0, 255, 0, digital_tlv),
+SOC_SINGLE_TLV("Playback Attenuation Volume", WM8955_DAC_CONTROL, 7, 1, 1,
+              atten_tlv),
+SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0,
+                   wm8955_get_deemph, wm8955_put_deemph),
+
+SOC_ENUM("Bass Mode", bass_mode),
+SOC_ENUM("Bass Cutoff", bass_cutoff),
+SOC_SINGLE("Bass Volume", WM8955_BASS_CONTROL, 0, 15, 1),
+
+SOC_ENUM("Treble Cutoff", treble_cutoff),
+SOC_SINGLE_TLV("Treble Volume", WM8955_TREBLE_CONTROL, 0, 14, 1, treble_tlv),
+
+SOC_SINGLE_TLV("Left Bypass Volume", WM8955_LEFT_OUT_MIX_1, 4, 7, 1,
+              bypass_tlv),
+SOC_SINGLE_TLV("Left Mono Volume", WM8955_LEFT_OUT_MIX_2, 4, 7, 1,
+              bypass_tlv),
+
+SOC_SINGLE_TLV("Right Mono Volume", WM8955_RIGHT_OUT_MIX_1, 4, 7, 1,
+              bypass_tlv),
+SOC_SINGLE_TLV("Right Bypass Volume", WM8955_RIGHT_OUT_MIX_2, 4, 7, 1,
+              bypass_tlv),
+
+/* Not a stereo pair so they line up with the DAPM switches */
+SOC_SINGLE_TLV("Mono Left Bypass Volume", WM8955_MONO_OUT_MIX_1, 4, 7, 1,
+              mono_tlv),
+SOC_SINGLE_TLV("Mono Right Bypass Volume", WM8955_MONO_OUT_MIX_2, 4, 7, 1,
+              mono_tlv),
+
+SOC_DOUBLE_R_TLV("Headphone Volume", WM8955_LOUT1_VOLUME,
+                WM8955_ROUT1_VOLUME, 0, 127, 0, out_tlv),
+SOC_DOUBLE_R("Headphone ZC Switch", WM8955_LOUT1_VOLUME,
+            WM8955_ROUT1_VOLUME, 7, 1, 0),
+
+SOC_DOUBLE_R_TLV("Speaker Volume", WM8955_LOUT2_VOLUME,
+                WM8955_ROUT2_VOLUME, 0, 127, 0, out_tlv),
+SOC_DOUBLE_R("Speaker ZC Switch", WM8955_LOUT2_VOLUME,
+            WM8955_ROUT2_VOLUME, 7, 1, 0),
+
+SOC_SINGLE_TLV("Mono Volume", WM8955_MONOOUT_VOLUME, 0, 127, 0, out_tlv),
+SOC_SINGLE("Mono ZC Switch", WM8955_MONOOUT_VOLUME, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new lmixer[] = {
+SOC_DAPM_SINGLE("Playback Switch", WM8955_LEFT_OUT_MIX_1, 8, 1, 0),
+SOC_DAPM_SINGLE("Bypass Switch", WM8955_LEFT_OUT_MIX_1, 7, 1, 0),
+SOC_DAPM_SINGLE("Right Playback Switch", WM8955_LEFT_OUT_MIX_2, 8, 1, 0),
+SOC_DAPM_SINGLE("Mono Switch", WM8955_LEFT_OUT_MIX_2, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new rmixer[] = {
+SOC_DAPM_SINGLE("Left Playback Switch", WM8955_RIGHT_OUT_MIX_1, 8, 1, 0),
+SOC_DAPM_SINGLE("Mono Switch", WM8955_RIGHT_OUT_MIX_1, 7, 1, 0),
+SOC_DAPM_SINGLE("Playback Switch", WM8955_RIGHT_OUT_MIX_2, 8, 1, 0),
+SOC_DAPM_SINGLE("Bypass Switch", WM8955_RIGHT_OUT_MIX_2, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new mmixer[] = {
+SOC_DAPM_SINGLE("Left Playback Switch", WM8955_MONO_OUT_MIX_1, 8, 1, 0),
+SOC_DAPM_SINGLE("Left Bypass Switch", WM8955_MONO_OUT_MIX_1, 7, 1, 0),
+SOC_DAPM_SINGLE("Right Playback Switch", WM8955_MONO_OUT_MIX_2, 8, 1, 0),
+SOC_DAPM_SINGLE("Right Bypass Switch", WM8955_MONO_OUT_MIX_2, 7, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8955_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("MONOIN-"),
+SND_SOC_DAPM_INPUT("MONOIN+"),
+SND_SOC_DAPM_INPUT("LINEINR"),
+SND_SOC_DAPM_INPUT("LINEINL"),
+
+SND_SOC_DAPM_PGA("Mono Input", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_SUPPLY("SYSCLK", WM8955_POWER_MANAGEMENT_1, 0, 1, wm8955_sysclk,
+                   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("TSDEN", WM8955_ADDITIONAL_CONTROL_1, 8, 0, NULL, 0),
+
+SND_SOC_DAPM_DAC("DACL", "Playback", WM8955_POWER_MANAGEMENT_2, 8, 0),
+SND_SOC_DAPM_DAC("DACR", "Playback", WM8955_POWER_MANAGEMENT_2, 7, 0),
+
+SND_SOC_DAPM_PGA("LOUT1 PGA", WM8955_POWER_MANAGEMENT_2, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ROUT1 PGA", WM8955_POWER_MANAGEMENT_2, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA("LOUT2 PGA", WM8955_POWER_MANAGEMENT_2, 4, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ROUT2 PGA", WM8955_POWER_MANAGEMENT_2, 3, 0, NULL, 0),
+SND_SOC_DAPM_PGA("MOUT PGA", WM8955_POWER_MANAGEMENT_2, 2, 0, NULL, 0),
+SND_SOC_DAPM_PGA("OUT3 PGA", WM8955_POWER_MANAGEMENT_2, 1, 0, NULL, 0),
+
+/* The names are chosen to make the control names nice */
+SND_SOC_DAPM_MIXER("Left", SND_SOC_NOPM, 0, 0,
+                  lmixer, ARRAY_SIZE(lmixer)),
+SND_SOC_DAPM_MIXER("Right", SND_SOC_NOPM, 0, 0,
+                  rmixer, ARRAY_SIZE(rmixer)),
+SND_SOC_DAPM_MIXER("Mono", SND_SOC_NOPM, 0, 0,
+                  mmixer, ARRAY_SIZE(mmixer)),
+
+SND_SOC_DAPM_OUTPUT("LOUT1"),
+SND_SOC_DAPM_OUTPUT("ROUT1"),
+SND_SOC_DAPM_OUTPUT("LOUT2"),
+SND_SOC_DAPM_OUTPUT("ROUT2"),
+SND_SOC_DAPM_OUTPUT("MONOOUT"),
+SND_SOC_DAPM_OUTPUT("OUT3"),
+};
+
+static const struct snd_soc_dapm_route wm8955_intercon[] = {
+       { "DACL", NULL, "SYSCLK" },
+       { "DACR", NULL, "SYSCLK" },
+
+       { "Mono Input", NULL, "MONOIN-" },
+       { "Mono Input", NULL, "MONOIN+" },
+
+       { "Left", "Playback Switch", "DACL" },
+       { "Left", "Right Playback Switch", "DACR" },
+       { "Left", "Bypass Switch", "LINEINL" },
+       { "Left", "Mono Switch", "Mono Input" },
+
+       { "Right", "Playback Switch", "DACR" },
+       { "Right", "Left Playback Switch", "DACL" },
+       { "Right", "Bypass Switch", "LINEINR" },
+       { "Right", "Mono Switch", "Mono Input" },
+
+       { "Mono", "Left Playback Switch", "DACL" },
+       { "Mono", "Right Playback Switch", "DACR" },
+       { "Mono", "Left Bypass Switch", "LINEINL" },
+       { "Mono", "Right Bypass Switch", "LINEINR" },
+
+       { "LOUT1 PGA", NULL, "Left" },
+       { "LOUT1", NULL, "TSDEN" },
+       { "LOUT1", NULL, "LOUT1 PGA" },
+
+       { "ROUT1 PGA", NULL, "Right" },
+       { "ROUT1", NULL, "TSDEN" },
+       { "ROUT1", NULL, "ROUT1 PGA" },
+
+       { "LOUT2 PGA", NULL, "Left" },
+       { "LOUT2", NULL, "TSDEN" },
+       { "LOUT2", NULL, "LOUT2 PGA" },
+
+       { "ROUT2 PGA", NULL, "Right" },
+       { "ROUT2", NULL, "TSDEN" },
+       { "ROUT2", NULL, "ROUT2 PGA" },
+
+       { "MOUT PGA", NULL, "Mono" },
+       { "MONOOUT", NULL, "MOUT PGA" },
+
+       /* OUT3 not currently implemented */
+       { "OUT3", NULL, "OUT3 PGA" },
+};
+
+static int wm8955_add_widgets(struct snd_soc_codec *codec)
+{
+       snd_soc_add_controls(codec, wm8955_snd_controls,
+                            ARRAY_SIZE(wm8955_snd_controls));
+
+       snd_soc_dapm_new_controls(codec, wm8955_dapm_widgets,
+                                 ARRAY_SIZE(wm8955_dapm_widgets));
+
+       snd_soc_dapm_add_routes(codec, wm8955_intercon,
+                               ARRAY_SIZE(wm8955_intercon));
+
+       return 0;
+}
+
+static int wm8955_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 wm8955_priv *wm8955 = codec->private_data;
+       int ret;
+       int wl;
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               wl = 0;
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               wl = 0x4;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               wl = 0x8;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               wl = 0xc;
+               break;
+       default:
+               return -EINVAL;
+       }
+       snd_soc_update_bits(codec, WM8955_AUDIO_INTERFACE,
+                           WM8955_WL_MASK, wl);
+
+       wm8955->fs = params_rate(params);
+       wm8955_set_deemph(codec);
+
+       /* If the chip is clocked then disable the clocks and force a
+        * reconfiguration, otherwise DAPM will power up the
+        * clocks for us later. */
+       ret = snd_soc_read(codec, WM8955_POWER_MANAGEMENT_1);
+       if (ret < 0)
+               return ret;
+       if (ret & WM8955_DIGENB) {
+               snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1,
+                                   WM8955_DIGENB, 0);
+               snd_soc_update_bits(codec, WM8955_CLOCKING_PLL,
+                                   WM8955_PLL_RB | WM8955_PLLEN, 0);
+
+               wm8955_configure_clocking(codec);
+       }
+
+       return 0;
+}
+
+
+static int wm8955_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+                            unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct wm8955_priv *priv = codec->private_data;
+       int div;
+
+       switch (clk_id) {
+       case WM8955_CLK_MCLK:
+               if (freq > 15000000) {
+                       priv->mclk_rate = freq /= 2;
+                       div = WM8955_MCLKDIV2;
+               } else {
+                       priv->mclk_rate = freq;
+                       div = 0;
+               }
+
+               snd_soc_update_bits(codec, WM8955_SAMPLE_RATE,
+                                   WM8955_MCLKDIV2, div);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       dev_dbg(dai->dev, "Clock source is %d at %uHz\n", clk_id, freq);
+
+       return 0;
+}
+
+static int wm8955_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       u16 aif = 0;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               aif |= WM8955_MS;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_B:
+               aif |= WM8955_LRP;
+       case SND_SOC_DAIFMT_DSP_A:
+               aif |= 0x3;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               aif |= 0x2;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               aif |= 0x1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_A:
+       case SND_SOC_DAIFMT_DSP_B:
+               /* frame inversion not valid for DSP modes */
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       aif |= WM8955_BCLKINV;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+
+       case SND_SOC_DAIFMT_I2S:
+       case SND_SOC_DAIFMT_RIGHT_J:
+       case SND_SOC_DAIFMT_LEFT_J:
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       break;
+               case SND_SOC_DAIFMT_IB_IF:
+                       aif |= WM8955_BCLKINV | WM8955_LRP;
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       aif |= WM8955_BCLKINV;
+                       break;
+               case SND_SOC_DAIFMT_NB_IF:
+                       aif |= WM8955_LRP;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, WM8955_AUDIO_INTERFACE,
+                           WM8955_MS | WM8955_FORMAT_MASK | WM8955_BCLKINV |
+                           WM8955_LRP, aif);
+
+       return 0;
+}
+
+
+static int wm8955_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       int val;
+
+       if (mute)
+               val = WM8955_DACMU;
+       else
+               val = 0;
+
+       snd_soc_update_bits(codec, WM8955_DAC_CONTROL, WM8955_DACMU, val);
+
+       return 0;
+}
+
+static int wm8955_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       struct wm8955_priv *wm8955 = codec->private_data;
+       int ret, i;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+
+       case SND_SOC_BIAS_PREPARE:
+               /* VMID resistance 2*50k */
+               snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1,
+                                   WM8955_VMIDSEL_MASK,
+                                   0x1 << WM8955_VMIDSEL_SHIFT);
+
+               /* Default bias current */
+               snd_soc_update_bits(codec, WM8955_ADDITIONAL_CONTROL_1,
+                                   WM8955_VSEL_MASK,
+                                   0x2 << WM8955_VSEL_SHIFT);
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+                       ret = regulator_bulk_enable(ARRAY_SIZE(wm8955->supplies),
+                                                   wm8955->supplies);
+                       if (ret != 0) {
+                               dev_err(codec->dev,
+                                       "Failed to enable supplies: %d\n",
+                                       ret);
+                               return ret;
+                       }
+
+                       /* Sync back cached values if they're
+                        * different from the hardware default.
+                        */
+                       for (i = 0; i < ARRAY_SIZE(wm8955->reg_cache); i++) {
+                               if (i == WM8955_RESET)
+                                       continue;
+
+                               if (wm8955->reg_cache[i] == wm8955_reg[i])
+                                       continue;
+
+                               snd_soc_write(codec, i, wm8955->reg_cache[i]);
+                       }
+
+                       /* Enable VREF and VMID */
+                       snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1,
+                                           WM8955_VREF |
+                                           WM8955_VMIDSEL_MASK,
+                                           WM8955_VREF |
+                                           0x3 << WM8955_VREF_SHIFT);
+
+                       /* Let VMID ramp */
+                       msleep(500);
+
+                       /* High resistance VROI to maintain outputs */
+                       snd_soc_update_bits(codec,
+                                           WM8955_ADDITIONAL_CONTROL_3,
+                                           WM8955_VROI, WM8955_VROI);
+               }
+
+               /* Maintain VMID with 2*250k */
+               snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1,
+                                   WM8955_VMIDSEL_MASK,
+                                   0x2 << WM8955_VMIDSEL_SHIFT);
+
+               /* Minimum bias current */
+               snd_soc_update_bits(codec, WM8955_ADDITIONAL_CONTROL_1,
+                                   WM8955_VSEL_MASK, 0);
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               /* Low resistance VROI to help discharge */
+               snd_soc_update_bits(codec,
+                                   WM8955_ADDITIONAL_CONTROL_3,
+                                   WM8955_VROI, 0);
+
+               /* Turn off VMID and VREF */
+               snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1,
+                                   WM8955_VREF |
+                                   WM8955_VMIDSEL_MASK, 0);
+
+               regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies),
+                                      wm8955->supplies);
+               break;
+       }
+       codec->bias_level = level;
+       return 0;
+}
+
+#define WM8955_RATES SNDRV_PCM_RATE_8000_96000
+
+#define WM8955_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 wm8955_dai_ops = {
+       .set_sysclk = wm8955_set_sysclk,
+       .set_fmt = wm8955_set_fmt,
+       .hw_params = wm8955_hw_params,
+       .digital_mute = wm8955_digital_mute,
+};
+
+struct snd_soc_dai wm8955_dai = {
+       .name = "WM8955",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = WM8955_RATES,
+               .formats = WM8955_FORMATS,
+       },
+       .ops = &wm8955_dai_ops,
+};
+EXPORT_SYMBOL_GPL(wm8955_dai);
+
+#ifdef CONFIG_PM
+static int wm8955_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;
+
+       wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       return 0;
+}
+
+static int wm8955_resume(struct platform_device *pdev)
+{
+       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;
+}
+#else
+#define wm8955_suspend NULL
+#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)
+{
+       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");
+               return -EINVAL;
+       }
+
+       mutex_init(&codec->mutex);
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+
+       codec->private_data = 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));
+
+       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(wm8955->supplies); i++)
+               wm8955->supplies[i].supply = wm8955_supply_names[i];
+
+       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8955->supplies),
+                                wm8955->supplies);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+               goto err;
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(wm8955->supplies),
+                                   wm8955->supplies);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+               goto err_get;
+       }
+
+       ret = wm8955_reset(codec);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+               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;
+       wm8955->reg_cache[WM8955_LOUT1_VOLUME] |= WM8955_LO1VU | WM8955_LO1ZC;
+       wm8955->reg_cache[WM8955_ROUT1_VOLUME] |= WM8955_RO1VU | WM8955_RO1ZC;
+       wm8955->reg_cache[WM8955_LOUT2_VOLUME] |= WM8955_LO2VU | WM8955_LO2ZC;
+       wm8955->reg_cache[WM8955_ROUT2_VOLUME] |= WM8955_RO2VU | WM8955_RO2ZC;
+       wm8955->reg_cache[WM8955_MONOOUT_VOLUME] |= WM8955_MOZC;
+
+       /* Also enable adaptive bass boost by default */
+       wm8955->reg_cache[WM8955_BASS_CONTROL] |= WM8955_BB;
+
+       /* Set platform data values */
+       if (wm8955->pdata) {
+               if (wm8955->pdata->out2_speaker)
+                       wm8955->reg_cache[WM8955_ADDITIONAL_CONTROL_2]
+                               |= WM8955_ROUT2INV;
+
+               if (wm8955->pdata->monoin_diff)
+                       wm8955->reg_cache[WM8955_MONO_OUT_MIX_1]
+                               |= WM8955_DMEN;
+       }
+
+       wm8955_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       /* 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);
+               return ret;
+       }
+
+       ret = snd_soc_register_dai(&wm8955_dai);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
+               snd_soc_unregister_codec(codec);
+               return ret;
+       }
+
+       return 0;
+
+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)
+{
+       wm8955_set_bias_level(&wm8955->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;
+}
+
+#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;
+
+       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);
+}
+
+static __devexit int wm8955_i2c_remove(struct i2c_client *client)
+{
+       struct wm8955_priv *wm8955 = i2c_get_clientdata(client);
+       wm8955_unregister(wm8955);
+       return 0;
+}
+
+static const struct i2c_device_id wm8955_i2c_id[] = {
+       { "wm8955", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8955_i2c_id);
+
+static struct i2c_driver wm8955_i2c_driver = {
+       .driver = {
+               .name = "wm8955",
+               .owner = THIS_MODULE,
+       },
+       .probe =    wm8955_i2c_probe,
+       .remove =   __devexit_p(wm8955_i2c_remove),
+       .id_table = wm8955_i2c_id,
+};
+#endif
+
+static int __init wm8955_modinit(void)
+{
+       int ret;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&wm8955_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register WM8955 I2C driver: %d\n",
+                      ret);
+       }
+#endif
+       return 0;
+}
+module_init(wm8955_modinit);
+
+static void __exit wm8955_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&wm8955_i2c_driver);
+#endif
+}
+module_exit(wm8955_exit);
+
+MODULE_DESCRIPTION("ASoC WM8955 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8955.h b/sound/soc/codecs/wm8955.h
new file mode 100644 (file)
index 0000000..ae349c8
--- /dev/null
@@ -0,0 +1,489 @@
+/*
+ * wm8955.h  --  WM8904 ASoC driver
+ *
+ * Copyright 2009 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 _WM8955_H
+#define _WM8955_H
+
+#define WM8955_CLK_MCLK 1
+
+extern struct snd_soc_dai wm8955_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8955;
+
+/*
+ * Register values.
+ */
+#define WM8955_LOUT1_VOLUME                     0x02
+#define WM8955_ROUT1_VOLUME                     0x03
+#define WM8955_DAC_CONTROL                      0x05
+#define WM8955_AUDIO_INTERFACE                  0x07
+#define WM8955_SAMPLE_RATE                      0x08
+#define WM8955_LEFT_DAC_VOLUME                  0x0A
+#define WM8955_RIGHT_DAC_VOLUME                 0x0B
+#define WM8955_BASS_CONTROL                     0x0C
+#define WM8955_TREBLE_CONTROL                   0x0D
+#define WM8955_RESET                            0x0F
+#define WM8955_ADDITIONAL_CONTROL_1             0x17
+#define WM8955_ADDITIONAL_CONTROL_2             0x18
+#define WM8955_POWER_MANAGEMENT_1               0x19
+#define WM8955_POWER_MANAGEMENT_2               0x1A
+#define WM8955_ADDITIONAL_CONTROL_3             0x1B
+#define WM8955_LEFT_OUT_MIX_1                   0x22
+#define WM8955_LEFT_OUT_MIX_2                   0x23
+#define WM8955_RIGHT_OUT_MIX_1                  0x24
+#define WM8955_RIGHT_OUT_MIX_2                  0x25
+#define WM8955_MONO_OUT_MIX_1                   0x26
+#define WM8955_MONO_OUT_MIX_2                   0x27
+#define WM8955_LOUT2_VOLUME                     0x28
+#define WM8955_ROUT2_VOLUME                     0x29
+#define WM8955_MONOOUT_VOLUME                   0x2A
+#define WM8955_CLOCKING_PLL                     0x2B
+#define WM8955_PLL_CONTROL_1                    0x2C
+#define WM8955_PLL_CONTROL_2                    0x2D
+#define WM8955_PLL_CONTROL_3                    0x2E
+#define WM8955_PLL_CONTROL_4                    0x3B
+
+#define WM8955_REGISTER_COUNT                   29
+#define WM8955_MAX_REGISTER                     0x3B
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R2 (0x02) - LOUT1 volume
+ */
+#define WM8955_LO1VU                            0x0100  /* LO1VU */
+#define WM8955_LO1VU_MASK                       0x0100  /* LO1VU */
+#define WM8955_LO1VU_SHIFT                           8  /* LO1VU */
+#define WM8955_LO1VU_WIDTH                           1  /* LO1VU */
+#define WM8955_LO1ZC                            0x0080  /* LO1ZC */
+#define WM8955_LO1ZC_MASK                       0x0080  /* LO1ZC */
+#define WM8955_LO1ZC_SHIFT                           7  /* LO1ZC */
+#define WM8955_LO1ZC_WIDTH                           1  /* LO1ZC */
+#define WM8955_LOUTVOL_MASK                     0x007F  /* LOUTVOL - [6:0] */
+#define WM8955_LOUTVOL_SHIFT                         0  /* LOUTVOL - [6:0] */
+#define WM8955_LOUTVOL_WIDTH                         7  /* LOUTVOL - [6:0] */
+
+/*
+ * R3 (0x03) - ROUT1 volume
+ */
+#define WM8955_RO1VU                            0x0100  /* RO1VU */
+#define WM8955_RO1VU_MASK                       0x0100  /* RO1VU */
+#define WM8955_RO1VU_SHIFT                           8  /* RO1VU */
+#define WM8955_RO1VU_WIDTH                           1  /* RO1VU */
+#define WM8955_RO1ZC                            0x0080  /* RO1ZC */
+#define WM8955_RO1ZC_MASK                       0x0080  /* RO1ZC */
+#define WM8955_RO1ZC_SHIFT                           7  /* RO1ZC */
+#define WM8955_RO1ZC_WIDTH                           1  /* RO1ZC */
+#define WM8955_ROUTVOL_MASK                     0x007F  /* ROUTVOL - [6:0] */
+#define WM8955_ROUTVOL_SHIFT                         0  /* ROUTVOL - [6:0] */
+#define WM8955_ROUTVOL_WIDTH                         7  /* ROUTVOL - [6:0] */
+
+/*
+ * R5 (0x05) - DAC Control
+ */
+#define WM8955_DAT                              0x0080  /* DAT */
+#define WM8955_DAT_MASK                         0x0080  /* DAT */
+#define WM8955_DAT_SHIFT                             7  /* DAT */
+#define WM8955_DAT_WIDTH                             1  /* DAT */
+#define WM8955_DACMU                            0x0008  /* DACMU */
+#define WM8955_DACMU_MASK                       0x0008  /* DACMU */
+#define WM8955_DACMU_SHIFT                           3  /* DACMU */
+#define WM8955_DACMU_WIDTH                           1  /* DACMU */
+#define WM8955_DEEMPH_MASK                      0x0006  /* DEEMPH - [2:1] */
+#define WM8955_DEEMPH_SHIFT                          1  /* DEEMPH - [2:1] */
+#define WM8955_DEEMPH_WIDTH                          2  /* DEEMPH - [2:1] */
+
+/*
+ * R7 (0x07) - Audio Interface
+ */
+#define WM8955_BCLKINV                          0x0080  /* BCLKINV */
+#define WM8955_BCLKINV_MASK                     0x0080  /* BCLKINV */
+#define WM8955_BCLKINV_SHIFT                         7  /* BCLKINV */
+#define WM8955_BCLKINV_WIDTH                         1  /* BCLKINV */
+#define WM8955_MS                               0x0040  /* MS */
+#define WM8955_MS_MASK                          0x0040  /* MS */
+#define WM8955_MS_SHIFT                              6  /* MS */
+#define WM8955_MS_WIDTH                              1  /* MS */
+#define WM8955_LRSWAP                           0x0020  /* LRSWAP */
+#define WM8955_LRSWAP_MASK                      0x0020  /* LRSWAP */
+#define WM8955_LRSWAP_SHIFT                          5  /* LRSWAP */
+#define WM8955_LRSWAP_WIDTH                          1  /* LRSWAP */
+#define WM8955_LRP                              0x0010  /* LRP */
+#define WM8955_LRP_MASK                         0x0010  /* LRP */
+#define WM8955_LRP_SHIFT                             4  /* LRP */
+#define WM8955_LRP_WIDTH                             1  /* LRP */
+#define WM8955_WL_MASK                          0x000C  /* WL - [3:2] */
+#define WM8955_WL_SHIFT                              2  /* WL - [3:2] */
+#define WM8955_WL_WIDTH                              2  /* WL - [3:2] */
+#define WM8955_FORMAT_MASK                      0x0003  /* FORMAT - [1:0] */
+#define WM8955_FORMAT_SHIFT                          0  /* FORMAT - [1:0] */
+#define WM8955_FORMAT_WIDTH                          2  /* FORMAT - [1:0] */
+
+/*
+ * R8 (0x08) - Sample Rate
+ */
+#define WM8955_BCLKDIV2                         0x0080  /* BCLKDIV2 */
+#define WM8955_BCLKDIV2_MASK                    0x0080  /* BCLKDIV2 */
+#define WM8955_BCLKDIV2_SHIFT                        7  /* BCLKDIV2 */
+#define WM8955_BCLKDIV2_WIDTH                        1  /* BCLKDIV2 */
+#define WM8955_MCLKDIV2                         0x0040  /* MCLKDIV2 */
+#define WM8955_MCLKDIV2_MASK                    0x0040  /* MCLKDIV2 */
+#define WM8955_MCLKDIV2_SHIFT                        6  /* MCLKDIV2 */
+#define WM8955_MCLKDIV2_WIDTH                        1  /* MCLKDIV2 */
+#define WM8955_SR_MASK                          0x003E  /* SR - [5:1] */
+#define WM8955_SR_SHIFT                              1  /* SR - [5:1] */
+#define WM8955_SR_WIDTH                              5  /* SR - [5:1] */
+#define WM8955_USB                              0x0001  /* USB */
+#define WM8955_USB_MASK                         0x0001  /* USB */
+#define WM8955_USB_SHIFT                             0  /* USB */
+#define WM8955_USB_WIDTH                             1  /* USB */
+
+/*
+ * R10 (0x0A) - Left DAC volume
+ */
+#define WM8955_LDVU                             0x0100  /* LDVU */
+#define WM8955_LDVU_MASK                        0x0100  /* LDVU */
+#define WM8955_LDVU_SHIFT                            8  /* LDVU */
+#define WM8955_LDVU_WIDTH                            1  /* LDVU */
+#define WM8955_LDACVOL_MASK                     0x00FF  /* LDACVOL - [7:0] */
+#define WM8955_LDACVOL_SHIFT                         0  /* LDACVOL - [7:0] */
+#define WM8955_LDACVOL_WIDTH                         8  /* LDACVOL - [7:0] */
+
+/*
+ * R11 (0x0B) - Right DAC volume
+ */
+#define WM8955_RDVU                             0x0100  /* RDVU */
+#define WM8955_RDVU_MASK                        0x0100  /* RDVU */
+#define WM8955_RDVU_SHIFT                            8  /* RDVU */
+#define WM8955_RDVU_WIDTH                            1  /* RDVU */
+#define WM8955_RDACVOL_MASK                     0x00FF  /* RDACVOL - [7:0] */
+#define WM8955_RDACVOL_SHIFT                         0  /* RDACVOL - [7:0] */
+#define WM8955_RDACVOL_WIDTH                         8  /* RDACVOL - [7:0] */
+
+/*
+ * R12 (0x0C) - Bass control
+ */
+#define WM8955_BB                               0x0080  /* BB */
+#define WM8955_BB_MASK                          0x0080  /* BB */
+#define WM8955_BB_SHIFT                              7  /* BB */
+#define WM8955_BB_WIDTH                              1  /* BB */
+#define WM8955_BC                               0x0040  /* BC */
+#define WM8955_BC_MASK                          0x0040  /* BC */
+#define WM8955_BC_SHIFT                              6  /* BC */
+#define WM8955_BC_WIDTH                              1  /* BC */
+#define WM8955_BASS_MASK                        0x000F  /* BASS - [3:0] */
+#define WM8955_BASS_SHIFT                            0  /* BASS - [3:0] */
+#define WM8955_BASS_WIDTH                            4  /* BASS - [3:0] */
+
+/*
+ * R13 (0x0D) - Treble control
+ */
+#define WM8955_TC                               0x0040  /* TC */
+#define WM8955_TC_MASK                          0x0040  /* TC */
+#define WM8955_TC_SHIFT                              6  /* TC */
+#define WM8955_TC_WIDTH                              1  /* TC */
+#define WM8955_TRBL_MASK                        0x000F  /* TRBL - [3:0] */
+#define WM8955_TRBL_SHIFT                            0  /* TRBL - [3:0] */
+#define WM8955_TRBL_WIDTH                            4  /* TRBL - [3:0] */
+
+/*
+ * R15 (0x0F) - Reset
+ */
+#define WM8955_RESET_MASK                       0x01FF  /* RESET - [8:0] */
+#define WM8955_RESET_SHIFT                           0  /* RESET - [8:0] */
+#define WM8955_RESET_WIDTH                           9  /* RESET - [8:0] */
+
+/*
+ * R23 (0x17) - Additional control (1)
+ */
+#define WM8955_TSDEN                            0x0100  /* TSDEN */
+#define WM8955_TSDEN_MASK                       0x0100  /* TSDEN */
+#define WM8955_TSDEN_SHIFT                           8  /* TSDEN */
+#define WM8955_TSDEN_WIDTH                           1  /* TSDEN */
+#define WM8955_VSEL_MASK                        0x00C0  /* VSEL - [7:6] */
+#define WM8955_VSEL_SHIFT                            6  /* VSEL - [7:6] */
+#define WM8955_VSEL_WIDTH                            2  /* VSEL - [7:6] */
+#define WM8955_DMONOMIX_MASK                    0x0030  /* DMONOMIX - [5:4] */
+#define WM8955_DMONOMIX_SHIFT                        4  /* DMONOMIX - [5:4] */
+#define WM8955_DMONOMIX_WIDTH                        2  /* DMONOMIX - [5:4] */
+#define WM8955_DACINV                           0x0002  /* DACINV */
+#define WM8955_DACINV_MASK                      0x0002  /* DACINV */
+#define WM8955_DACINV_SHIFT                          1  /* DACINV */
+#define WM8955_DACINV_WIDTH                          1  /* DACINV */
+#define WM8955_TOEN                             0x0001  /* TOEN */
+#define WM8955_TOEN_MASK                        0x0001  /* TOEN */
+#define WM8955_TOEN_SHIFT                            0  /* TOEN */
+#define WM8955_TOEN_WIDTH                            1  /* TOEN */
+
+/*
+ * R24 (0x18) - Additional control (2)
+ */
+#define WM8955_OUT3SW_MASK                      0x0180  /* OUT3SW - [8:7] */
+#define WM8955_OUT3SW_SHIFT                          7  /* OUT3SW - [8:7] */
+#define WM8955_OUT3SW_WIDTH                          2  /* OUT3SW - [8:7] */
+#define WM8955_ROUT2INV                         0x0010  /* ROUT2INV */
+#define WM8955_ROUT2INV_MASK                    0x0010  /* ROUT2INV */
+#define WM8955_ROUT2INV_SHIFT                        4  /* ROUT2INV */
+#define WM8955_ROUT2INV_WIDTH                        1  /* ROUT2INV */
+#define WM8955_DACOSR                           0x0001  /* DACOSR */
+#define WM8955_DACOSR_MASK                      0x0001  /* DACOSR */
+#define WM8955_DACOSR_SHIFT                          0  /* DACOSR */
+#define WM8955_DACOSR_WIDTH                          1  /* DACOSR */
+
+/*
+ * R25 (0x19) - Power Management (1)
+ */
+#define WM8955_VMIDSEL_MASK                     0x0180  /* VMIDSEL - [8:7] */
+#define WM8955_VMIDSEL_SHIFT                         7  /* VMIDSEL - [8:7] */
+#define WM8955_VMIDSEL_WIDTH                         2  /* VMIDSEL - [8:7] */
+#define WM8955_VREF                             0x0040  /* VREF */
+#define WM8955_VREF_MASK                        0x0040  /* VREF */
+#define WM8955_VREF_SHIFT                            6  /* VREF */
+#define WM8955_VREF_WIDTH                            1  /* VREF */
+#define WM8955_DIGENB                           0x0001  /* DIGENB */
+#define WM8955_DIGENB_MASK                      0x0001  /* DIGENB */
+#define WM8955_DIGENB_SHIFT                          0  /* DIGENB */
+#define WM8955_DIGENB_WIDTH                          1  /* DIGENB */
+
+/*
+ * R26 (0x1A) - Power Management (2)
+ */
+#define WM8955_DACL                             0x0100  /* DACL */
+#define WM8955_DACL_MASK                        0x0100  /* DACL */
+#define WM8955_DACL_SHIFT                            8  /* DACL */
+#define WM8955_DACL_WIDTH                            1  /* DACL */
+#define WM8955_DACR                             0x0080  /* DACR */
+#define WM8955_DACR_MASK                        0x0080  /* DACR */
+#define WM8955_DACR_SHIFT                            7  /* DACR */
+#define WM8955_DACR_WIDTH                            1  /* DACR */
+#define WM8955_LOUT1                            0x0040  /* LOUT1 */
+#define WM8955_LOUT1_MASK                       0x0040  /* LOUT1 */
+#define WM8955_LOUT1_SHIFT                           6  /* LOUT1 */
+#define WM8955_LOUT1_WIDTH                           1  /* LOUT1 */
+#define WM8955_ROUT1                            0x0020  /* ROUT1 */
+#define WM8955_ROUT1_MASK                       0x0020  /* ROUT1 */
+#define WM8955_ROUT1_SHIFT                           5  /* ROUT1 */
+#define WM8955_ROUT1_WIDTH                           1  /* ROUT1 */
+#define WM8955_LOUT2                            0x0010  /* LOUT2 */
+#define WM8955_LOUT2_MASK                       0x0010  /* LOUT2 */
+#define WM8955_LOUT2_SHIFT                           4  /* LOUT2 */
+#define WM8955_LOUT2_WIDTH                           1  /* LOUT2 */
+#define WM8955_ROUT2                            0x0008  /* ROUT2 */
+#define WM8955_ROUT2_MASK                       0x0008  /* ROUT2 */
+#define WM8955_ROUT2_SHIFT                           3  /* ROUT2 */
+#define WM8955_ROUT2_WIDTH                           1  /* ROUT2 */
+#define WM8955_MONO                             0x0004  /* MONO */
+#define WM8955_MONO_MASK                        0x0004  /* MONO */
+#define WM8955_MONO_SHIFT                            2  /* MONO */
+#define WM8955_MONO_WIDTH                            1  /* MONO */
+#define WM8955_OUT3                             0x0002  /* OUT3 */
+#define WM8955_OUT3_MASK                        0x0002  /* OUT3 */
+#define WM8955_OUT3_SHIFT                            1  /* OUT3 */
+#define WM8955_OUT3_WIDTH                            1  /* OUT3 */
+
+/*
+ * R27 (0x1B) - Additional Control (3)
+ */
+#define WM8955_VROI                             0x0040  /* VROI */
+#define WM8955_VROI_MASK                        0x0040  /* VROI */
+#define WM8955_VROI_SHIFT                            6  /* VROI */
+#define WM8955_VROI_WIDTH                            1  /* VROI */
+
+/*
+ * R34 (0x22) - Left out Mix (1)
+ */
+#define WM8955_LD2LO                            0x0100  /* LD2LO */
+#define WM8955_LD2LO_MASK                       0x0100  /* LD2LO */
+#define WM8955_LD2LO_SHIFT                           8  /* LD2LO */
+#define WM8955_LD2LO_WIDTH                           1  /* LD2LO */
+#define WM8955_LI2LO                            0x0080  /* LI2LO */
+#define WM8955_LI2LO_MASK                       0x0080  /* LI2LO */
+#define WM8955_LI2LO_SHIFT                           7  /* LI2LO */
+#define WM8955_LI2LO_WIDTH                           1  /* LI2LO */
+#define WM8955_LI2LOVOL_MASK                    0x0070  /* LI2LOVOL - [6:4] */
+#define WM8955_LI2LOVOL_SHIFT                        4  /* LI2LOVOL - [6:4] */
+#define WM8955_LI2LOVOL_WIDTH                        3  /* LI2LOVOL - [6:4] */
+
+/*
+ * R35 (0x23) - Left out Mix (2)
+ */
+#define WM8955_RD2LO                            0x0100  /* RD2LO */
+#define WM8955_RD2LO_MASK                       0x0100  /* RD2LO */
+#define WM8955_RD2LO_SHIFT                           8  /* RD2LO */
+#define WM8955_RD2LO_WIDTH                           1  /* RD2LO */
+#define WM8955_RI2LO                            0x0080  /* RI2LO */
+#define WM8955_RI2LO_MASK                       0x0080  /* RI2LO */
+#define WM8955_RI2LO_SHIFT                           7  /* RI2LO */
+#define WM8955_RI2LO_WIDTH                           1  /* RI2LO */
+#define WM8955_RI2LOVOL_MASK                    0x0070  /* RI2LOVOL - [6:4] */
+#define WM8955_RI2LOVOL_SHIFT                        4  /* RI2LOVOL - [6:4] */
+#define WM8955_RI2LOVOL_WIDTH                        3  /* RI2LOVOL - [6:4] */
+
+/*
+ * R36 (0x24) - Right out Mix (1)
+ */
+#define WM8955_LD2RO                            0x0100  /* LD2RO */
+#define WM8955_LD2RO_MASK                       0x0100  /* LD2RO */
+#define WM8955_LD2RO_SHIFT                           8  /* LD2RO */
+#define WM8955_LD2RO_WIDTH                           1  /* LD2RO */
+#define WM8955_LI2RO                            0x0080  /* LI2RO */
+#define WM8955_LI2RO_MASK                       0x0080  /* LI2RO */
+#define WM8955_LI2RO_SHIFT                           7  /* LI2RO */
+#define WM8955_LI2RO_WIDTH                           1  /* LI2RO */
+#define WM8955_LI2ROVOL_MASK                    0x0070  /* LI2ROVOL - [6:4] */
+#define WM8955_LI2ROVOL_SHIFT                        4  /* LI2ROVOL - [6:4] */
+#define WM8955_LI2ROVOL_WIDTH                        3  /* LI2ROVOL - [6:4] */
+
+/*
+ * R37 (0x25) - Right Out Mix (2)
+ */
+#define WM8955_RD2RO                            0x0100  /* RD2RO */
+#define WM8955_RD2RO_MASK                       0x0100  /* RD2RO */
+#define WM8955_RD2RO_SHIFT                           8  /* RD2RO */
+#define WM8955_RD2RO_WIDTH                           1  /* RD2RO */
+#define WM8955_RI2RO                            0x0080  /* RI2RO */
+#define WM8955_RI2RO_MASK                       0x0080  /* RI2RO */
+#define WM8955_RI2RO_SHIFT                           7  /* RI2RO */
+#define WM8955_RI2RO_WIDTH                           1  /* RI2RO */
+#define WM8955_RI2ROVOL_MASK                    0x0070  /* RI2ROVOL - [6:4] */
+#define WM8955_RI2ROVOL_SHIFT                        4  /* RI2ROVOL - [6:4] */
+#define WM8955_RI2ROVOL_WIDTH                        3  /* RI2ROVOL - [6:4] */
+
+/*
+ * R38 (0x26) - Mono out Mix (1)
+ */
+#define WM8955_LD2MO                            0x0100  /* LD2MO */
+#define WM8955_LD2MO_MASK                       0x0100  /* LD2MO */
+#define WM8955_LD2MO_SHIFT                           8  /* LD2MO */
+#define WM8955_LD2MO_WIDTH                           1  /* LD2MO */
+#define WM8955_LI2MO                            0x0080  /* LI2MO */
+#define WM8955_LI2MO_MASK                       0x0080  /* LI2MO */
+#define WM8955_LI2MO_SHIFT                           7  /* LI2MO */
+#define WM8955_LI2MO_WIDTH                           1  /* LI2MO */
+#define WM8955_LI2MOVOL_MASK                    0x0070  /* LI2MOVOL - [6:4] */
+#define WM8955_LI2MOVOL_SHIFT                        4  /* LI2MOVOL - [6:4] */
+#define WM8955_LI2MOVOL_WIDTH                        3  /* LI2MOVOL - [6:4] */
+#define WM8955_DMEN                             0x0001  /* DMEN */
+#define WM8955_DMEN_MASK                        0x0001  /* DMEN */
+#define WM8955_DMEN_SHIFT                            0  /* DMEN */
+#define WM8955_DMEN_WIDTH                            1  /* DMEN */
+
+/*
+ * R39 (0x27) - Mono out Mix (2)
+ */
+#define WM8955_RD2MO                            0x0100  /* RD2MO */
+#define WM8955_RD2MO_MASK                       0x0100  /* RD2MO */
+#define WM8955_RD2MO_SHIFT                           8  /* RD2MO */
+#define WM8955_RD2MO_WIDTH                           1  /* RD2MO */
+#define WM8955_RI2MO                            0x0080  /* RI2MO */
+#define WM8955_RI2MO_MASK                       0x0080  /* RI2MO */
+#define WM8955_RI2MO_SHIFT                           7  /* RI2MO */
+#define WM8955_RI2MO_WIDTH                           1  /* RI2MO */
+#define WM8955_RI2MOVOL_MASK                    0x0070  /* RI2MOVOL - [6:4] */
+#define WM8955_RI2MOVOL_SHIFT                        4  /* RI2MOVOL - [6:4] */
+#define WM8955_RI2MOVOL_WIDTH                        3  /* RI2MOVOL - [6:4] */
+
+/*
+ * R40 (0x28) - LOUT2 volume
+ */
+#define WM8955_LO2VU                            0x0100  /* LO2VU */
+#define WM8955_LO2VU_MASK                       0x0100  /* LO2VU */
+#define WM8955_LO2VU_SHIFT                           8  /* LO2VU */
+#define WM8955_LO2VU_WIDTH                           1  /* LO2VU */
+#define WM8955_LO2ZC                            0x0080  /* LO2ZC */
+#define WM8955_LO2ZC_MASK                       0x0080  /* LO2ZC */
+#define WM8955_LO2ZC_SHIFT                           7  /* LO2ZC */
+#define WM8955_LO2ZC_WIDTH                           1  /* LO2ZC */
+#define WM8955_LOUT2VOL_MASK                    0x007F  /* LOUT2VOL - [6:0] */
+#define WM8955_LOUT2VOL_SHIFT                        0  /* LOUT2VOL - [6:0] */
+#define WM8955_LOUT2VOL_WIDTH                        7  /* LOUT2VOL - [6:0] */
+
+/*
+ * R41 (0x29) - ROUT2 volume
+ */
+#define WM8955_RO2VU                            0x0100  /* RO2VU */
+#define WM8955_RO2VU_MASK                       0x0100  /* RO2VU */
+#define WM8955_RO2VU_SHIFT                           8  /* RO2VU */
+#define WM8955_RO2VU_WIDTH                           1  /* RO2VU */
+#define WM8955_RO2ZC                            0x0080  /* RO2ZC */
+#define WM8955_RO2ZC_MASK                       0x0080  /* RO2ZC */
+#define WM8955_RO2ZC_SHIFT                           7  /* RO2ZC */
+#define WM8955_RO2ZC_WIDTH                           1  /* RO2ZC */
+#define WM8955_ROUT2VOL_MASK                    0x007F  /* ROUT2VOL - [6:0] */
+#define WM8955_ROUT2VOL_SHIFT                        0  /* ROUT2VOL - [6:0] */
+#define WM8955_ROUT2VOL_WIDTH                        7  /* ROUT2VOL - [6:0] */
+
+/*
+ * R42 (0x2A) - MONOOUT volume
+ */
+#define WM8955_MOZC                             0x0080  /* MOZC */
+#define WM8955_MOZC_MASK                        0x0080  /* MOZC */
+#define WM8955_MOZC_SHIFT                            7  /* MOZC */
+#define WM8955_MOZC_WIDTH                            1  /* MOZC */
+#define WM8955_MOUTVOL_MASK                     0x007F  /* MOUTVOL - [6:0] */
+#define WM8955_MOUTVOL_SHIFT                         0  /* MOUTVOL - [6:0] */
+#define WM8955_MOUTVOL_WIDTH                         7  /* MOUTVOL - [6:0] */
+
+/*
+ * R43 (0x2B) - Clocking / PLL
+ */
+#define WM8955_MCLKSEL                          0x0100  /* MCLKSEL */
+#define WM8955_MCLKSEL_MASK                     0x0100  /* MCLKSEL */
+#define WM8955_MCLKSEL_SHIFT                         8  /* MCLKSEL */
+#define WM8955_MCLKSEL_WIDTH                         1  /* MCLKSEL */
+#define WM8955_PLLOUTDIV2                       0x0020  /* PLLOUTDIV2 */
+#define WM8955_PLLOUTDIV2_MASK                  0x0020  /* PLLOUTDIV2 */
+#define WM8955_PLLOUTDIV2_SHIFT                      5  /* PLLOUTDIV2 */
+#define WM8955_PLLOUTDIV2_WIDTH                      1  /* PLLOUTDIV2 */
+#define WM8955_PLL_RB                           0x0010  /* PLL_RB */
+#define WM8955_PLL_RB_MASK                      0x0010  /* PLL_RB */
+#define WM8955_PLL_RB_SHIFT                          4  /* PLL_RB */
+#define WM8955_PLL_RB_WIDTH                          1  /* PLL_RB */
+#define WM8955_PLLEN                            0x0008  /* PLLEN */
+#define WM8955_PLLEN_MASK                       0x0008  /* PLLEN */
+#define WM8955_PLLEN_SHIFT                           3  /* PLLEN */
+#define WM8955_PLLEN_WIDTH                           1  /* PLLEN */
+
+/*
+ * R44 (0x2C) - PLL Control 1
+ */
+#define WM8955_N_MASK                           0x01E0  /* N - [8:5] */
+#define WM8955_N_SHIFT                               5  /* N - [8:5] */
+#define WM8955_N_WIDTH                               4  /* N - [8:5] */
+#define WM8955_K_21_18_MASK                     0x000F  /* K(21:18) - [3:0] */
+#define WM8955_K_21_18_SHIFT                         0  /* K(21:18) - [3:0] */
+#define WM8955_K_21_18_WIDTH                         4  /* K(21:18) - [3:0] */
+
+/*
+ * R45 (0x2D) - PLL Control 2
+ */
+#define WM8955_K_17_9_MASK                      0x01FF  /* K(17:9) - [8:0] */
+#define WM8955_K_17_9_SHIFT                          0  /* K(17:9) - [8:0] */
+#define WM8955_K_17_9_WIDTH                          9  /* K(17:9) - [8:0] */
+
+/*
+ * R46 (0x2E) - PLL Control 3
+ */
+#define WM8955_K_8_0_MASK                       0x01FF  /* K(8:0) - [8:0] */
+#define WM8955_K_8_0_SHIFT                           0  /* K(8:0) - [8:0] */
+#define WM8955_K_8_0_WIDTH                           9  /* K(8:0) - [8:0] */
+
+/*
+ * R59 (0x3B) - PLL Control 4
+ */
+#define WM8955_KEN                              0x0080  /* KEN */
+#define WM8955_KEN_MASK                         0x0080  /* KEN */
+#define WM8955_KEN_SHIFT                             7  /* KEN */
+#define WM8955_KEN_WIDTH                             1  /* KEN */
+
+#endif
index a8007d58813f77b4687223fe40f48820e4b71561..d2342c5e0425f2e861d8861d80cffd2a3b81ef1a 100644 (file)
@@ -1022,6 +1022,9 @@ static int wm8961_resume(struct platform_device *pdev)
        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;
 
index 8812751da8c9838c484ffe66ae1d0e0eb8858546..ee637af4737a039c252c82c287f5c37e22b4ee37 100644 (file)
@@ -170,6 +170,10 @@ SOC_ENUM("Aux Mode", wm8974_auxmode),
 
 SOC_SINGLE("Capture Boost(+20dB)", WM8974_ADCBOOST,  8, 1, 0),
 SOC_SINGLE("Mono Playback Switch", WM8974_MONOMIX, 6, 1, 1),
+
+/* DAC / ADC oversampling */
+SOC_SINGLE("DAC 128x Oversampling Switch", WM8974_DAC, 8, 1, 0),
+SOC_SINGLE("ADC 128x Oversampling Switch", WM8974_ADC, 8, 1, 0),
 };
 
 /* Speaker Output Mixer */
@@ -381,14 +385,6 @@ static int wm8974_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
                reg = snd_soc_read(codec, WM8974_CLOCK) & 0x11f;
                snd_soc_write(codec, WM8974_CLOCK, reg | div);
                break;
-       case WM8974_ADCCLK:
-               reg = snd_soc_read(codec, WM8974_ADC) & 0x1f7;
-               snd_soc_write(codec, WM8974_ADC, reg | div);
-               break;
-       case WM8974_DACCLK:
-               reg = snd_soc_read(codec, WM8974_DAC) & 0x1f7;
-               snd_soc_write(codec, WM8974_DAC, reg | div);
-               break;
        case WM8974_BCLKDIV:
                reg = snd_soc_read(codec, WM8974_CLOCK) & 0x1e3;
                snd_soc_write(codec, WM8974_CLOCK, reg | div);
index 98de9562d4d240bae85d158563f6279d45819ae7..896a7f0f3fc4b189e0537bb6f7765639e2957b65 100644 (file)
 /* Clock divider Id's */
 #define WM8974_OPCLKDIV                0
 #define WM8974_MCLKDIV         1
-#define WM8974_ADCCLK          2
-#define WM8974_DACCLK          3
-#define WM8974_BCLKDIV         4
-
-/* DAC clock dividers */
-#define WM8974_DACCLK_F2       (1 << 3)
-#define WM8974_DACCLK_F4       (0 << 3)
-
-/* ADC clock dividers */
-#define WM8974_ADCCLK_F2       (1 << 3)
-#define WM8974_ADCCLK_F4       (0 << 3)
+#define WM8974_BCLKDIV         2
 
 /* PLL Out dividers */
 #define WM8974_OPCLKDIV_1      (0 << 4)
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
new file mode 100644 (file)
index 0000000..28bb59e
--- /dev/null
@@ -0,0 +1,1149 @@
+/*
+ * wm8978.c  --  WM8978 ALSA SoC Audio Codec driver
+ *
+ * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ * Copyright (C) 2007 Carlos Munoz <carlos@kenati.com>
+ * Copyright 2006-2009 Wolfson Microelectronics PLC.
+ * Based on wm8974 and wm8990 by Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/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 <asm/div64.h>
+
+#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 */
+       0x0050, 0x0000, 0x0140, 0x0000, /* 0x04...0x07 */
+       0x0000, 0x0000, 0x0000, 0x00ff, /* 0x08...0x0b */
+       0x00ff, 0x0000, 0x0100, 0x00ff, /* 0x0c...0x0f */
+       0x00ff, 0x0000, 0x012c, 0x002c, /* 0x10...0x13 */
+       0x002c, 0x002c, 0x002c, 0x0000, /* 0x14...0x17 */
+       0x0032, 0x0000, 0x0000, 0x0000, /* 0x18...0x1b */
+       0x0000, 0x0000, 0x0000, 0x0000, /* 0x1c...0x1f */
+       0x0038, 0x000b, 0x0032, 0x0000, /* 0x20...0x23 */
+       0x0008, 0x000c, 0x0093, 0x00e9, /* 0x24...0x27 */
+       0x0000, 0x0000, 0x0000, 0x0000, /* 0x28...0x2b */
+       0x0033, 0x0010, 0x0010, 0x0100, /* 0x2c...0x2f */
+       0x0100, 0x0002, 0x0001, 0x0001, /* 0x30...0x33 */
+       0x0039, 0x0039, 0x0039, 0x0039, /* 0x34...0x37 */
+       0x0001, 0x0001,                 /* 0x38...0x3b */
+};
+
+/* codec private data */
+struct wm8978_priv {
+       struct snd_soc_codec codec;
+       unsigned int f_pllout;
+       unsigned int f_mclk;
+       unsigned int f_256fs;
+       unsigned int f_opclk;
+       int mclk_idx;
+       enum wm8978_sysclk_src sysclk;
+       u16 reg_cache[WM8978_CACHEREGNUM];
+};
+
+static const char *wm8978_companding[] = {"Off", "NC", "u-law", "A-law"};
+static const char *wm8978_eqmode[] = {"Capture", "Playback"};
+static const char *wm8978_bw[] = {"Narrow", "Wide"};
+static const char *wm8978_eq1[] = {"80Hz", "105Hz", "135Hz", "175Hz"};
+static const char *wm8978_eq2[] = {"230Hz", "300Hz", "385Hz", "500Hz"};
+static const char *wm8978_eq3[] = {"650Hz", "850Hz", "1.1kHz", "1.4kHz"};
+static const char *wm8978_eq4[] = {"1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz"};
+static const char *wm8978_eq5[] = {"5.3kHz", "6.9kHz", "9kHz", "11.7kHz"};
+static const char *wm8978_alc3[] = {"ALC", "Limiter"};
+static const char *wm8978_alc1[] = {"Off", "Right", "Left", "Both"};
+
+static const SOC_ENUM_SINGLE_DECL(adc_compand, WM8978_COMPANDING_CONTROL, 1,
+                                 wm8978_companding);
+static const SOC_ENUM_SINGLE_DECL(dac_compand, WM8978_COMPANDING_CONTROL, 3,
+                                 wm8978_companding);
+static const SOC_ENUM_SINGLE_DECL(eqmode, WM8978_EQ1, 8, wm8978_eqmode);
+static const SOC_ENUM_SINGLE_DECL(eq1, WM8978_EQ1, 5, wm8978_eq1);
+static const SOC_ENUM_SINGLE_DECL(eq2bw, WM8978_EQ2, 8, wm8978_bw);
+static const SOC_ENUM_SINGLE_DECL(eq2, WM8978_EQ2, 5, wm8978_eq2);
+static const SOC_ENUM_SINGLE_DECL(eq3bw, WM8978_EQ3, 8, wm8978_bw);
+static const SOC_ENUM_SINGLE_DECL(eq3, WM8978_EQ3, 5, wm8978_eq3);
+static const SOC_ENUM_SINGLE_DECL(eq4bw, WM8978_EQ4, 8, wm8978_bw);
+static const SOC_ENUM_SINGLE_DECL(eq4, WM8978_EQ4, 5, wm8978_eq4);
+static const SOC_ENUM_SINGLE_DECL(eq5, WM8978_EQ5, 5, wm8978_eq5);
+static const SOC_ENUM_SINGLE_DECL(alc3, WM8978_ALC_CONTROL_3, 8, wm8978_alc3);
+static const SOC_ENUM_SINGLE_DECL(alc1, WM8978_ALC_CONTROL_1, 7, wm8978_alc1);
+
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1200, 75, 0);
+static const DECLARE_TLV_DB_SCALE(spk_tlv, -5700, 100, 0);
+static const DECLARE_TLV_DB_SCALE(boost_tlv, -1500, 300, 1);
+
+static const struct snd_kcontrol_new wm8978_snd_controls[] = {
+
+       SOC_SINGLE("Digital Loopback Switch",
+               WM8978_COMPANDING_CONTROL, 0, 1, 0),
+
+       SOC_ENUM("ADC Companding", adc_compand),
+       SOC_ENUM("DAC Companding", dac_compand),
+
+       SOC_DOUBLE("DAC Inversion Switch", WM8978_DAC_CONTROL, 0, 1, 1, 0),
+
+       SOC_DOUBLE_R_TLV("PCM Volume",
+               WM8978_LEFT_DAC_DIGITAL_VOLUME, WM8978_RIGHT_DAC_DIGITAL_VOLUME,
+               0, 255, 0, digital_tlv),
+
+       SOC_SINGLE("High Pass Filter Switch", WM8978_ADC_CONTROL, 8, 1, 0),
+       SOC_SINGLE("High Pass Cut Off", WM8978_ADC_CONTROL, 4, 7, 0),
+       SOC_DOUBLE("ADC Inversion Switch", WM8978_ADC_CONTROL, 0, 1, 1, 0),
+
+       SOC_DOUBLE_R_TLV("ADC Volume",
+               WM8978_LEFT_ADC_DIGITAL_VOLUME, WM8978_RIGHT_ADC_DIGITAL_VOLUME,
+               0, 255, 0, digital_tlv),
+
+       SOC_ENUM("Equaliser Function", eqmode),
+       SOC_ENUM("EQ1 Cut Off", eq1),
+       SOC_SINGLE_TLV("EQ1 Volume", WM8978_EQ1,  0, 24, 1, eq_tlv),
+
+       SOC_ENUM("Equaliser EQ2 Bandwith", eq2bw),
+       SOC_ENUM("EQ2 Cut Off", eq2),
+       SOC_SINGLE_TLV("EQ2 Volume", WM8978_EQ2,  0, 24, 1, eq_tlv),
+
+       SOC_ENUM("Equaliser EQ3 Bandwith", eq3bw),
+       SOC_ENUM("EQ3 Cut Off", eq3),
+       SOC_SINGLE_TLV("EQ3 Volume", WM8978_EQ3,  0, 24, 1, eq_tlv),
+
+       SOC_ENUM("Equaliser EQ4 Bandwith", eq4bw),
+       SOC_ENUM("EQ4 Cut Off", eq4),
+       SOC_SINGLE_TLV("EQ4 Volume", WM8978_EQ4,  0, 24, 1, eq_tlv),
+
+       SOC_ENUM("EQ5 Cut Off", eq5),
+       SOC_SINGLE_TLV("EQ5 Volume", WM8978_EQ5, 0, 24, 1, eq_tlv),
+
+       SOC_SINGLE("DAC Playback Limiter Switch",
+               WM8978_DAC_LIMITER_1, 8, 1, 0),
+       SOC_SINGLE("DAC Playback Limiter Decay",
+               WM8978_DAC_LIMITER_1, 4, 15, 0),
+       SOC_SINGLE("DAC Playback Limiter Attack",
+               WM8978_DAC_LIMITER_1, 0, 15, 0),
+
+       SOC_SINGLE("DAC Playback Limiter Threshold",
+               WM8978_DAC_LIMITER_2, 4, 7, 0),
+       SOC_SINGLE("DAC Playback Limiter Boost",
+               WM8978_DAC_LIMITER_2, 0, 15, 0),
+
+       SOC_ENUM("ALC Enable Switch", alc1),
+       SOC_SINGLE("ALC Capture Min Gain", WM8978_ALC_CONTROL_1, 0, 7, 0),
+       SOC_SINGLE("ALC Capture Max Gain", WM8978_ALC_CONTROL_1, 3, 7, 0),
+
+       SOC_SINGLE("ALC Capture Hold", WM8978_ALC_CONTROL_2, 4, 7, 0),
+       SOC_SINGLE("ALC Capture Target", WM8978_ALC_CONTROL_2, 0, 15, 0),
+
+       SOC_ENUM("ALC Capture Mode", alc3),
+       SOC_SINGLE("ALC Capture Decay", WM8978_ALC_CONTROL_3, 4, 15, 0),
+       SOC_SINGLE("ALC Capture Attack", WM8978_ALC_CONTROL_3, 0, 15, 0),
+
+       SOC_SINGLE("ALC Capture Noise Gate Switch", WM8978_NOISE_GATE, 3, 1, 0),
+       SOC_SINGLE("ALC Capture Noise Gate Threshold",
+               WM8978_NOISE_GATE, 0, 7, 0),
+
+       SOC_DOUBLE_R("Capture PGA ZC Switch",
+               WM8978_LEFT_INP_PGA_CONTROL, WM8978_RIGHT_INP_PGA_CONTROL,
+               7, 1, 0),
+
+       /* OUT1 - Headphones */
+       SOC_DOUBLE_R("Headphone Playback ZC Switch",
+               WM8978_LOUT1_HP_CONTROL, WM8978_ROUT1_HP_CONTROL, 7, 1, 0),
+
+       SOC_DOUBLE_R_TLV("Headphone Playback Volume",
+               WM8978_LOUT1_HP_CONTROL, WM8978_ROUT1_HP_CONTROL,
+               0, 63, 0, spk_tlv),
+
+       /* OUT2 - Speakers */
+       SOC_DOUBLE_R("Speaker Playback ZC Switch",
+               WM8978_LOUT2_SPK_CONTROL, WM8978_ROUT2_SPK_CONTROL, 7, 1, 0),
+
+       SOC_DOUBLE_R_TLV("Speaker Playback Volume",
+               WM8978_LOUT2_SPK_CONTROL, WM8978_ROUT2_SPK_CONTROL,
+               0, 63, 0, spk_tlv),
+
+       /* OUT3/4 - Line Output */
+       SOC_DOUBLE_R("Line Playback Switch",
+               WM8978_OUT3_MIXER_CONTROL, WM8978_OUT4_MIXER_CONTROL, 6, 1, 1),
+
+       /* Mixer #3: Boost (Input) mixer */
+       SOC_DOUBLE_R("PGA Boost (+20dB)",
+               WM8978_LEFT_ADC_BOOST_CONTROL, WM8978_RIGHT_ADC_BOOST_CONTROL,
+               8, 1, 0),
+       SOC_DOUBLE_R_TLV("L2/R2 Boost Volume",
+               WM8978_LEFT_ADC_BOOST_CONTROL, WM8978_RIGHT_ADC_BOOST_CONTROL,
+               4, 7, 0, boost_tlv),
+       SOC_DOUBLE_R_TLV("Aux Boost Volume",
+               WM8978_LEFT_ADC_BOOST_CONTROL, WM8978_RIGHT_ADC_BOOST_CONTROL,
+               0, 7, 0, boost_tlv),
+
+       /* Input PGA volume */
+       SOC_DOUBLE_R_TLV("Input PGA Volume",
+               WM8978_LEFT_INP_PGA_CONTROL, WM8978_RIGHT_INP_PGA_CONTROL,
+               0, 63, 0, inpga_tlv),
+
+       /* Headphone */
+       SOC_DOUBLE_R("Headphone Switch",
+               WM8978_LOUT1_HP_CONTROL, WM8978_ROUT1_HP_CONTROL, 6, 1, 1),
+
+       /* Speaker */
+       SOC_DOUBLE_R("Speaker Switch",
+               WM8978_LOUT2_SPK_CONTROL, WM8978_ROUT2_SPK_CONTROL, 6, 1, 1),
+
+       /* DAC / ADC oversampling */
+       SOC_SINGLE("DAC 128x Oversampling Switch", WM8978_DAC_CONTROL, 8, 1, 0),
+       SOC_SINGLE("ADC 128x Oversampling Switch", WM8978_ADC_CONTROL, 8, 1, 0),
+};
+
+/* Mixer #1: Output (OUT1, OUT2) Mixer: mix AUX, Input mixer output and DAC */
+static const struct snd_kcontrol_new wm8978_left_out_mixer[] = {
+       SOC_DAPM_SINGLE("Line Bypass Switch", WM8978_LEFT_MIXER_CONTROL, 1, 1, 0),
+       SOC_DAPM_SINGLE("Aux Playback Switch", WM8978_LEFT_MIXER_CONTROL, 5, 1, 0),
+       SOC_DAPM_SINGLE("PCM Playback Switch", WM8978_LEFT_MIXER_CONTROL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8978_right_out_mixer[] = {
+       SOC_DAPM_SINGLE("Line Bypass Switch", WM8978_RIGHT_MIXER_CONTROL, 1, 1, 0),
+       SOC_DAPM_SINGLE("Aux Playback Switch", WM8978_RIGHT_MIXER_CONTROL, 5, 1, 0),
+       SOC_DAPM_SINGLE("PCM Playback Switch", WM8978_RIGHT_MIXER_CONTROL, 0, 1, 0),
+};
+
+/* OUT3/OUT4 Mixer not implemented */
+
+/* Mixer #2: Input PGA Mute */
+static const struct snd_kcontrol_new wm8978_left_input_mixer[] = {
+       SOC_DAPM_SINGLE("L2 Switch", WM8978_INPUT_CONTROL, 2, 1, 0),
+       SOC_DAPM_SINGLE("MicN Switch", WM8978_INPUT_CONTROL, 1, 1, 0),
+       SOC_DAPM_SINGLE("MicP Switch", WM8978_INPUT_CONTROL, 0, 1, 0),
+};
+static const struct snd_kcontrol_new wm8978_right_input_mixer[] = {
+       SOC_DAPM_SINGLE("R2 Switch", WM8978_INPUT_CONTROL, 6, 1, 0),
+       SOC_DAPM_SINGLE("MicN Switch", WM8978_INPUT_CONTROL, 5, 1, 0),
+       SOC_DAPM_SINGLE("MicP Switch", WM8978_INPUT_CONTROL, 4, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8978_dapm_widgets[] = {
+       SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback",
+                        WM8978_POWER_MANAGEMENT_3, 0, 0),
+       SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback",
+                        WM8978_POWER_MANAGEMENT_3, 1, 0),
+       SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture",
+                        WM8978_POWER_MANAGEMENT_2, 0, 0),
+       SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture",
+                        WM8978_POWER_MANAGEMENT_2, 1, 0),
+
+       /* Mixer #1: OUT1,2 */
+       SOC_MIXER_ARRAY("Left Output Mixer", WM8978_POWER_MANAGEMENT_3,
+                       2, 0, wm8978_left_out_mixer),
+       SOC_MIXER_ARRAY("Right Output Mixer", WM8978_POWER_MANAGEMENT_3,
+                       3, 0, wm8978_right_out_mixer),
+
+       SOC_MIXER_ARRAY("Left Input Mixer", WM8978_POWER_MANAGEMENT_2,
+                       2, 0, wm8978_left_input_mixer),
+       SOC_MIXER_ARRAY("Right Input Mixer", WM8978_POWER_MANAGEMENT_2,
+                       3, 0, wm8978_right_input_mixer),
+
+       SND_SOC_DAPM_PGA("Left Boost Mixer", WM8978_POWER_MANAGEMENT_2,
+                        4, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Right Boost Mixer", WM8978_POWER_MANAGEMENT_2,
+                        5, 0, NULL, 0),
+
+       SND_SOC_DAPM_PGA("Left Capture PGA", WM8978_LEFT_INP_PGA_CONTROL,
+                        6, 1, NULL, 0),
+       SND_SOC_DAPM_PGA("Right Capture PGA", WM8978_RIGHT_INP_PGA_CONTROL,
+                        6, 1, NULL, 0),
+
+       SND_SOC_DAPM_PGA("Left Headphone Out", WM8978_POWER_MANAGEMENT_2,
+                        7, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Right Headphone Out", WM8978_POWER_MANAGEMENT_2,
+                        8, 0, NULL, 0),
+
+       SND_SOC_DAPM_PGA("Left Speaker Out", WM8978_POWER_MANAGEMENT_3,
+                        6, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Right Speaker Out", WM8978_POWER_MANAGEMENT_3,
+                        5, 0, NULL, 0),
+
+       SND_SOC_DAPM_MIXER("OUT4 VMID", WM8978_POWER_MANAGEMENT_3,
+                          8, 0, NULL, 0),
+
+       SND_SOC_DAPM_MICBIAS("Mic Bias", WM8978_POWER_MANAGEMENT_1, 4, 0),
+
+       SND_SOC_DAPM_INPUT("LMICN"),
+       SND_SOC_DAPM_INPUT("LMICP"),
+       SND_SOC_DAPM_INPUT("RMICN"),
+       SND_SOC_DAPM_INPUT("RMICP"),
+       SND_SOC_DAPM_INPUT("LAUX"),
+       SND_SOC_DAPM_INPUT("RAUX"),
+       SND_SOC_DAPM_INPUT("L2"),
+       SND_SOC_DAPM_INPUT("R2"),
+       SND_SOC_DAPM_OUTPUT("LHP"),
+       SND_SOC_DAPM_OUTPUT("RHP"),
+       SND_SOC_DAPM_OUTPUT("LSPK"),
+       SND_SOC_DAPM_OUTPUT("RSPK"),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       /* Output mixer */
+       {"Right Output Mixer", "PCM Playback Switch", "Right DAC"},
+       {"Right Output Mixer", "Aux Playback Switch", "RAUX"},
+       {"Right Output Mixer", "Line Bypass Switch", "Right Boost Mixer"},
+
+       {"Left Output Mixer", "PCM Playback Switch", "Left DAC"},
+       {"Left Output Mixer", "Aux Playback Switch", "LAUX"},
+       {"Left Output Mixer", "Line Bypass Switch", "Left Boost Mixer"},
+
+       /* Outputs */
+       {"Right Headphone Out", NULL, "Right Output Mixer"},
+       {"RHP", NULL, "Right Headphone Out"},
+
+       {"Left Headphone Out", NULL, "Left Output Mixer"},
+       {"LHP", NULL, "Left Headphone Out"},
+
+       {"Right Speaker Out", NULL, "Right Output Mixer"},
+       {"RSPK", NULL, "Right Speaker Out"},
+
+       {"Left Speaker Out", NULL, "Left Output Mixer"},
+       {"LSPK", NULL, "Left Speaker Out"},
+
+       /* Boost Mixer */
+       {"Right ADC", NULL, "Right Boost Mixer"},
+
+       {"Right Boost Mixer", NULL, "RAUX"},
+       {"Right Boost Mixer", NULL, "Right Capture PGA"},
+       {"Right Boost Mixer", NULL, "R2"},
+
+       {"Left ADC", NULL, "Left Boost Mixer"},
+
+       {"Left Boost Mixer", NULL, "LAUX"},
+       {"Left Boost Mixer", NULL, "Left Capture PGA"},
+       {"Left Boost Mixer", NULL, "L2"},
+
+       /* Input PGA */
+       {"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", "RMICN"},
+       {"Right Input Mixer", "MicP Switch", "RMICP"},
+
+       {"Left Input Mixer", "L2 Switch", "L2"},
+       {"Left Input Mixer", "MicN Switch", "LMICN"},
+       {"Left Input Mixer", "MicP Switch", "LMICP"},
+};
+
+static int wm8978_add_widgets(struct snd_soc_codec *codec)
+{
+       snd_soc_dapm_new_controls(codec, wm8978_dapm_widgets,
+                                 ARRAY_SIZE(wm8978_dapm_widgets));
+
+       /* set up the WM8978 audio map */
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+       return 0;
+}
+
+/* PLL divisors */
+struct wm8978_pll_div {
+       u32 k;
+       u8 n;
+       u8 div2;
+};
+
+#define FIXED_PLL_SIZE (1 << 24)
+
+static void pll_factors(struct wm8978_pll_div *pll_div, unsigned int target,
+                       unsigned int source)
+{
+       u64 k_part;
+       unsigned int k, n_div, n_mod;
+
+       n_div = target / source;
+       if (n_div < 6) {
+               source >>= 1;
+               pll_div->div2 = 1;
+               n_div = target / source;
+       } else {
+               pll_div->div2 = 0;
+       }
+
+       if (n_div < 6 || n_div > 12)
+               dev_warn(wm8978_codec->dev,
+                        "WM8978 N value exceeds recommended range! N = %u\n",
+                        n_div);
+
+       pll_div->n = n_div;
+       n_mod = target - source * n_div;
+       k_part = FIXED_PLL_SIZE * (long long)n_mod + source / 2;
+
+       do_div(k_part, source);
+
+       k = k_part & 0xFFFFFFFF;
+
+       pll_div->k = k;
+}
+
+/* MCLK dividers */
+static const int mclk_numerator[]      = {1, 3, 2, 3, 4, 6, 8, 12};
+static const int mclk_denominator[]    = {1, 2, 1, 1, 1, 1, 1, 1};
+
+/*
+ * find index >= idx, such that, for a given f_out,
+ * 3 * f_mclk / 4 <= f_PLLOUT < 13 * f_mclk / 4
+ * f_out can be f_256fs or f_opclk, currently only used for f_256fs. Can be
+ * generalised for f_opclk with suitable coefficient arrays, but currently
+ * the OPCLK divisor is calculated directly, not iteratively.
+ */
+static int wm8978_enum_mclk(unsigned int f_out, unsigned int f_mclk,
+                           unsigned int *f_pllout)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(mclk_numerator); i++) {
+               unsigned int f_pllout_x4 = 4 * f_out * mclk_numerator[i] /
+                       mclk_denominator[i];
+               if (3 * f_mclk <= f_pllout_x4 && f_pllout_x4 < 13 * f_mclk) {
+                       *f_pllout = f_pllout_x4 / 4;
+                       return i;
+               }
+       }
+
+       return -EINVAL;
+}
+
+/*
+ * Calculate internal frequencies and dividers, according to Figure 40
+ * "PLL and Clock Select Circuit" in WM8978 datasheet Rev. 2.6
+ */
+static int wm8978_configure_pll(struct snd_soc_codec *codec)
+{
+       struct wm8978_priv *wm8978 = codec->private_data;
+       struct wm8978_pll_div pll_div;
+       unsigned int f_opclk = wm8978->f_opclk, f_mclk = wm8978->f_mclk,
+               f_256fs = wm8978->f_256fs;
+       unsigned int f2;
+
+       if (!f_mclk)
+               return -EINVAL;
+
+       if (f_opclk) {
+               unsigned int opclk_div;
+               /* Cannot set up MCLK divider now, do later */
+               wm8978->mclk_idx = -1;
+
+               /*
+                * The user needs OPCLK. Choose OPCLKDIV to put
+                * 6 <= R = f2 / f1 < 13, 1 <= OPCLKDIV <= 4.
+                * f_opclk = f_mclk * prescale * R / 4 / OPCLKDIV, where
+                * prescale = 1, or prescale = 2. Prescale is calculated inside
+                * pll_factors(). We have to select f_PLLOUT, such that
+                * f_mclk * 3 / 4 <= f_PLLOUT < f_mclk * 13 / 4. Must be
+                * f_mclk * 3 / 16 <= f_opclk < f_mclk * 13 / 4.
+                */
+               if (16 * f_opclk < 3 * f_mclk || 4 * f_opclk >= 13 * f_mclk)
+                       return -EINVAL;
+
+               if (4 * f_opclk < 3 * f_mclk)
+                       /* Have to use OPCLKDIV */
+                       opclk_div = (3 * f_mclk / 4 + f_opclk - 1) / f_opclk;
+               else
+                       opclk_div = 1;
+
+               dev_dbg(codec->dev, "%s: OPCLKDIV=%d\n", __func__, opclk_div);
+
+               snd_soc_update_bits(codec, WM8978_GPIO_CONTROL, 0x30,
+                                   (opclk_div - 1) << 4);
+
+               wm8978->f_pllout = f_opclk * opclk_div;
+       } else if (f_256fs) {
+               /*
+                * Not using OPCLK, but PLL is used for the codec, choose R:
+                * 6 <= R = f2 / f1 < 13, to put 1 <= MCLKDIV <= 12.
+                * f_256fs = f_mclk * prescale * R / 4 / MCLKDIV, where
+                * prescale = 1, or prescale = 2. Prescale is calculated inside
+                * pll_factors(). We have to select f_PLLOUT, such that
+                * f_mclk * 3 / 4 <= f_PLLOUT < f_mclk * 13 / 4. Must be
+                * f_mclk * 3 / 48 <= f_256fs < f_mclk * 13 / 4. This means MCLK
+                * must be 3.781MHz <= f_MCLK <= 32.768MHz
+                */
+               int idx = wm8978_enum_mclk(f_256fs, f_mclk, &wm8978->f_pllout);
+               if (idx < 0)
+                       return idx;
+
+               wm8978->mclk_idx = idx;
+
+               /* GPIO1 into default mode as input - before configuring PLL */
+               snd_soc_update_bits(codec, WM8978_GPIO_CONTROL, 7, 0);
+       } else {
+               return -EINVAL;
+       }
+
+       f2 = wm8978->f_pllout * 4;
+
+       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);
+
+       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);
+
+       /* Turn PLL off for configuration... */
+       snd_soc_update_bits(codec, WM8978_POWER_MANAGEMENT_1, 0x20, 0);
+
+       snd_soc_write(codec, WM8978_PLL_N, (pll_div.div2 << 4) | pll_div.n);
+       snd_soc_write(codec, WM8978_PLL_K1, pll_div.k >> 18);
+       snd_soc_write(codec, WM8978_PLL_K2, (pll_div.k >> 9) & 0x1ff);
+       snd_soc_write(codec, WM8978_PLL_K3, pll_div.k & 0x1ff);
+
+       /* ...and on again */
+       snd_soc_update_bits(codec, WM8978_POWER_MANAGEMENT_1, 0x20, 0x20);
+
+       if (f_opclk)
+               /* Output PLL (OPCLK) to GPIO1 */
+               snd_soc_update_bits(codec, WM8978_GPIO_CONTROL, 7, 4);
+
+       return 0;
+}
+
+/*
+ * Configure WM8978 clock dividers.
+ */
+static int wm8978_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+                                int div_id, int div)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct wm8978_priv *wm8978 = codec->private_data;
+       int ret = 0;
+
+       switch (div_id) {
+       case WM8978_OPCLKRATE:
+               wm8978->f_opclk = div;
+
+               if (wm8978->f_mclk)
+                       /*
+                        * We know the MCLK frequency, the user has requested
+                        * OPCLK, configure the PLL based on that and start it
+                        * and OPCLK immediately. We will configure PLL to match
+                        * user-requested OPCLK frquency as good as possible.
+                        * In fact, it is likely, that matching the sampling
+                        * rate, when it becomes known, is more important, and
+                        * we will not be reconfiguring PLL then, because we
+                        * must not interrupt OPCLK. But it should be fine,
+                        * because typically the user will request OPCLK to run
+                        * at 256fs or 512fs, and for these cases we will also
+                        * find an exact MCLK divider configuration - it will
+                        * be equal to or double the OPCLK divisor.
+                        */
+                       ret = wm8978_configure_pll(codec);
+               break;
+       case WM8978_BCLKDIV:
+               if (div & ~0x1c)
+                       return -EINVAL;
+               snd_soc_update_bits(codec, WM8978_CLOCKING, 0x1c, div);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       dev_dbg(codec->dev, "%s: ID %d, value %u\n", __func__, div_id, div);
+
+       return ret;
+}
+
+/*
+ * @freq:      when .set_pll() us not used, freq is codec MCLK input frequency
+ */
+static int wm8978_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 wm8978_priv *wm8978 = codec->private_data;
+       int ret = 0;
+
+       dev_dbg(codec->dev, "%s: ID %d, freq %u\n", __func__, clk_id, freq);
+
+       if (freq) {
+               wm8978->f_mclk = freq;
+
+               /* Even if MCLK is used for system clock, might have to drive OPCLK */
+               if (wm8978->f_opclk)
+                       ret = wm8978_configure_pll(codec);
+
+               /* Our sysclk is fixed to 256 * fs, will configure in .hw_params()  */
+
+               if (!ret)
+                       wm8978->sysclk = clk_id;
+       }
+
+       if (wm8978->sysclk == WM8978_PLL && (!freq || clk_id == WM8978_MCLK)) {
+               /* Clock CODEC directly from MCLK */
+               snd_soc_update_bits(codec, WM8978_CLOCKING, 0x100, 0);
+
+               /* GPIO1 into default mode as input - before configuring PLL */
+               snd_soc_update_bits(codec, WM8978_GPIO_CONTROL, 7, 0);
+
+               /* Turn off PLL */
+               snd_soc_update_bits(codec, WM8978_POWER_MANAGEMENT_1, 0x20, 0);
+               wm8978->sysclk = WM8978_MCLK;
+               wm8978->f_pllout = 0;
+               wm8978->f_opclk = 0;
+       }
+
+       return ret;
+}
+
+/*
+ * Set ADC and Voice DAC format.
+ */
+static int wm8978_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       /*
+        * BCLK polarity mask = 0x100, LRC clock polarity mask = 0x80,
+        * Data Format mask = 0x18: all will be calculated anew
+        */
+       u16 iface = snd_soc_read(codec, WM8978_AUDIO_INTERFACE) & ~0x198;
+       u16 clk = snd_soc_read(codec, WM8978_CLOCKING);
+
+       dev_dbg(codec->dev, "%s\n", __func__);
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               clk |= 1;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               clk &= ~1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* interface format */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               iface |= 0x10;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               iface |= 0x8;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               iface |= 0x18;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* clock inversion */
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               iface |= 0x180;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               iface |= 0x100;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               iface |= 0x80;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_write(codec, WM8978_AUDIO_INTERFACE, iface);
+       snd_soc_write(codec, WM8978_CLOCKING, clk);
+
+       return 0;
+}
+
+/*
+ * Set PCM DAI bit size and sample rate.
+ */
+static int wm8978_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 wm8978_priv *wm8978 = codec->private_data;
+       /* Word length mask = 0x60 */
+       u16 iface_ctl = snd_soc_read(codec, WM8978_AUDIO_INTERFACE) & ~0x60;
+       /* Sampling rate mask = 0xe (for filters) */
+       u16 add_ctl = snd_soc_read(codec, WM8978_ADDITIONAL_CONTROL) & ~0xe;
+       u16 clking = snd_soc_read(codec, WM8978_CLOCKING);
+       enum wm8978_sysclk_src current_clk_id = clking & 0x100 ?
+               WM8978_PLL : WM8978_MCLK;
+       unsigned int f_sel, diff, diff_best = INT_MAX;
+       int i, best = 0;
+
+       if (!wm8978->f_mclk)
+               return -EINVAL;
+
+       /* bit size */
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               iface_ctl |= 0x20;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               iface_ctl |= 0x40;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               iface_ctl |= 0x60;
+               break;
+       }
+
+       /* filter coefficient */
+       switch (params_rate(params)) {
+       case 8000:
+               add_ctl |= 0x5 << 1;
+               break;
+       case 11025:
+               add_ctl |= 0x4 << 1;
+               break;
+       case 16000:
+               add_ctl |= 0x3 << 1;
+               break;
+       case 22050:
+               add_ctl |= 0x2 << 1;
+               break;
+       case 32000:
+               add_ctl |= 0x1 << 1;
+               break;
+       case 44100:
+       case 48000:
+               break;
+       }
+
+       /* Sampling rate is known now, can configure the MCLK divider */
+       wm8978->f_256fs = params_rate(params) * 256;
+
+       if (wm8978->sysclk == WM8978_MCLK) {
+               wm8978->mclk_idx = -1;
+               f_sel = wm8978->f_mclk;
+       } else {
+               if (!wm8978->f_pllout) {
+                       /* We only enter here, if OPCLK is not used */
+                       int ret = wm8978_configure_pll(codec);
+                       if (ret < 0)
+                               return ret;
+               }
+               f_sel = wm8978->f_pllout;
+       }
+
+       if (wm8978->mclk_idx < 0) {
+               /* Either MCLK is used directly, or OPCLK is used */
+               if (f_sel < wm8978->f_256fs || f_sel > 12 * wm8978->f_256fs)
+                       return -EINVAL;
+
+               for (i = 0; i < ARRAY_SIZE(mclk_numerator); i++) {
+                       diff = abs(wm8978->f_256fs * 3 -
+                                  f_sel * 3 * mclk_denominator[i] / mclk_numerator[i]);
+
+                       if (diff < diff_best) {
+                               diff_best = diff;
+                               best = i;
+                       }
+
+                       if (!diff)
+                               break;
+               }
+       } else {
+               /* OPCLK not used, codec driven by PLL */
+               best = wm8978->mclk_idx;
+               diff = 0;
+       }
+
+       if (diff)
+               dev_warn(codec->dev, "Imprecise sampling rate: %uHz%s\n",
+                       f_sel * mclk_denominator[best] / mclk_numerator[best] / 256,
+                       wm8978->sysclk == WM8978_MCLK ?
+                       ", consider using PLL" : "");
+
+       dev_dbg(codec->dev, "%s: fmt %d, rate %u, MCLK divisor #%d\n", __func__,
+               params_format(params), params_rate(params), best);
+
+       /* MCLK divisor mask = 0xe0 */
+       snd_soc_update_bits(codec, WM8978_CLOCKING, 0xe0, best << 5);
+
+       snd_soc_write(codec, WM8978_AUDIO_INTERFACE, iface_ctl);
+       snd_soc_write(codec, WM8978_ADDITIONAL_CONTROL, add_ctl);
+
+       if (wm8978->sysclk != current_clk_id) {
+               if (wm8978->sysclk == WM8978_PLL)
+                       /* Run CODEC from PLL instead of MCLK */
+                       snd_soc_update_bits(codec, WM8978_CLOCKING,
+                                           0x100, 0x100);
+               else
+                       /* Clock CODEC directly from MCLK */
+                       snd_soc_update_bits(codec, WM8978_CLOCKING, 0x100, 0);
+       }
+
+       return 0;
+}
+
+static int wm8978_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+
+       dev_dbg(codec->dev, "%s: %d\n", __func__, mute);
+
+       if (mute)
+               snd_soc_update_bits(codec, WM8978_DAC_CONTROL, 0x40, 0x40);
+       else
+               snd_soc_update_bits(codec, WM8978_DAC_CONTROL, 0x40, 0);
+
+       return 0;
+}
+
+static int wm8978_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       u16 power1 = snd_soc_read(codec, WM8978_POWER_MANAGEMENT_1) & ~3;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+       case SND_SOC_BIAS_PREPARE:
+               power1 |= 1;  /* VMID 75k */
+               snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, power1);
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               /* bit 3: enable bias, bit 2: enable I/O tie off buffer */
+               power1 |= 0xc;
+
+               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+                       /* Initial cap charge at VMID 5k */
+                       snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1,
+                                     power1 | 0x3);
+                       mdelay(100);
+               }
+
+               power1 |= 0x2;  /* VMID 500k */
+               snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, power1);
+               break;
+       case SND_SOC_BIAS_OFF:
+               /* Preserve PLL - OPCLK may be used by someone */
+               snd_soc_update_bits(codec, WM8978_POWER_MANAGEMENT_1, ~0x20, 0);
+               snd_soc_write(codec, WM8978_POWER_MANAGEMENT_2, 0);
+               snd_soc_write(codec, WM8978_POWER_MANAGEMENT_3, 0);
+               break;
+       }
+
+       dev_dbg(codec->dev, "%s: %d, %x\n", __func__, level, power1);
+
+       codec->bias_level = level;
+       return 0;
+}
+
+#define WM8978_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 wm8978_dai_ops = {
+       .hw_params      = wm8978_hw_params,
+       .digital_mute   = wm8978_mute,
+       .set_fmt        = wm8978_set_dai_fmt,
+       .set_clkdiv     = wm8978_set_dai_clkdiv,
+       .set_sysclk     = wm8978_set_dai_sysclk,
+};
+
+/* Also supports 12kHz */
+struct snd_soc_dai wm8978_dai = {
+       .name = "WM8978 HiFi",
+       .id = 1,
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = WM8978_FORMATS,
+       },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = WM8978_FORMATS,
+       },
+       .ops = &wm8978_dai_ops,
+};
+EXPORT_SYMBOL_GPL(wm8978_dai);
+
+static int wm8978_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;
+
+       wm8978_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       /* Also switch PLL off */
+       snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, 0);
+
+       return 0;
+}
+
+static int wm8978_resume(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->card->codec;
+       struct wm8978_priv *wm8978 = codec->private_data;
+       int i;
+       u16 *cache = codec->reg_cache;
+
+       /* Sync reg_cache with the hardware */
+       for (i = 0; i < ARRAY_SIZE(wm8978_reg); i++) {
+               if (i == WM8978_RESET)
+                       continue;
+               if (cache[i] != wm8978_reg[i])
+                       snd_soc_write(codec, i, cache[i]);
+       }
+
+       wm8978_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       if (wm8978->f_pllout)
+               /* Switch PLL on */
+               snd_soc_update_bits(codec, WM8978_POWER_MANAGEMENT_1, 0x20, 0x20);
+
+       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
+ * the update bit is set, will also the volume be updated - simultaneously for
+ * both channels.
+ */
+static const int update_reg[] = {
+       WM8978_LEFT_DAC_DIGITAL_VOLUME,
+       WM8978_RIGHT_DAC_DIGITAL_VOLUME,
+       WM8978_LEFT_ADC_DIGITAL_VOLUME,
+       WM8978_RIGHT_ADC_DIGITAL_VOLUME,
+       WM8978_LEFT_INP_PGA_CONTROL,
+       WM8978_RIGHT_INP_PGA_CONTROL,
+       WM8978_LOUT1_HP_CONTROL,
+       WM8978_ROUT1_HP_CONTROL,
+       WM8978_LOUT2_SPK_CONTROL,
+       WM8978_ROUT2_SPK_CONTROL,
+};
+
+static __devinit int wm8978_register(struct wm8978_priv *wm8978)
+{
+       int ret, i;
+       struct snd_soc_codec *codec = &wm8978->codec;
+
+       if (wm8978_codec) {
+               dev_err(codec->dev, "Another WM8978 is registered\n");
+               return -EINVAL;
+       }
+
+       /*
+        * 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);
+
+       codec->private_data = 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;
+
+       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, 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
+        * written.
+        */
+       for (i = 0; i < ARRAY_SIZE(update_reg); i++)
+               ((u16 *)codec->reg_cache)[update_reg[i]] |= 0x100;
+
+       /* Reset the codec */
+       ret = snd_soc_write(codec, WM8978_RESET, 0);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to issue reset\n");
+               goto err;
+       }
+
+       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;
+       }
+
+       return 0;
+
+err_codec:
+       snd_soc_unregister_codec(codec);
+err:
+       kfree(wm8978);
+       return ret;
+}
+
+static __devexit void wm8978_unregister(struct wm8978_priv *wm8978)
+{
+       wm8978_set_bias_level(&wm8978->codec, SND_SOC_BIAS_OFF);
+       snd_soc_unregister_dai(&wm8978_dai);
+       snd_soc_unregister_codec(&wm8978->codec);
+       kfree(wm8978);
+       wm8978_codec = NULL;
+}
+
+static __devinit int wm8978_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
+{
+       struct wm8978_priv *wm8978;
+       struct snd_soc_codec *codec;
+
+       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;
+
+       return wm8978_register(wm8978);
+}
+
+static __devexit int wm8978_i2c_remove(struct i2c_client *client)
+{
+       struct wm8978_priv *wm8978 = i2c_get_clientdata(client);
+       wm8978_unregister(wm8978);
+       return 0;
+}
+
+static const struct i2c_device_id wm8978_i2c_id[] = {
+       { "wm8978", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8978_i2c_id);
+
+static struct i2c_driver wm8978_i2c_driver = {
+       .driver = {
+               .name = "WM8978",
+               .owner = THIS_MODULE,
+       },
+       .probe =    wm8978_i2c_probe,
+       .remove =   __devexit_p(wm8978_i2c_remove),
+       .id_table = wm8978_i2c_id,
+};
+
+static int __init wm8978_modinit(void)
+{
+       return i2c_add_driver(&wm8978_i2c_driver);
+}
+module_init(wm8978_modinit);
+
+static void __exit wm8978_exit(void)
+{
+       i2c_del_driver(&wm8978_i2c_driver);
+}
+module_exit(wm8978_exit);
+
+MODULE_DESCRIPTION("ASoC WM8978 codec driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8978.h b/sound/soc/codecs/wm8978.h
new file mode 100644 (file)
index 0000000..56ec832
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * wm8978.h            --  codec driver for WM8978
+ *
+ * Copyright 2009 Guennadi Liakhovetski <g.liakhovetski@gmx.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.
+ */
+
+#ifndef __WM8978_H__
+#define __WM8978_H__
+
+/*
+ * Register values.
+ */
+#define WM8978_RESET                           0x00
+#define WM8978_POWER_MANAGEMENT_1              0x01
+#define WM8978_POWER_MANAGEMENT_2              0x02
+#define WM8978_POWER_MANAGEMENT_3              0x03
+#define WM8978_AUDIO_INTERFACE                 0x04
+#define WM8978_COMPANDING_CONTROL              0x05
+#define WM8978_CLOCKING                                0x06
+#define WM8978_ADDITIONAL_CONTROL              0x07
+#define WM8978_GPIO_CONTROL                    0x08
+#define WM8978_JACK_DETECT_CONTROL_1           0x09
+#define WM8978_DAC_CONTROL                     0x0A
+#define WM8978_LEFT_DAC_DIGITAL_VOLUME         0x0B
+#define WM8978_RIGHT_DAC_DIGITAL_VOLUME                0x0C
+#define WM8978_JACK_DETECT_CONTROL_2           0x0D
+#define WM8978_ADC_CONTROL                     0x0E
+#define WM8978_LEFT_ADC_DIGITAL_VOLUME         0x0F
+#define WM8978_RIGHT_ADC_DIGITAL_VOLUME                0x10
+#define WM8978_EQ1                             0x12
+#define WM8978_EQ2                             0x13
+#define WM8978_EQ3                             0x14
+#define WM8978_EQ4                             0x15
+#define WM8978_EQ5                             0x16
+#define WM8978_DAC_LIMITER_1                   0x18
+#define WM8978_DAC_LIMITER_2                   0x19
+#define WM8978_NOTCH_FILTER_1                  0x1b
+#define WM8978_NOTCH_FILTER_2                  0x1c
+#define WM8978_NOTCH_FILTER_3                  0x1d
+#define WM8978_NOTCH_FILTER_4                  0x1e
+#define WM8978_ALC_CONTROL_1                   0x20
+#define WM8978_ALC_CONTROL_2                   0x21
+#define WM8978_ALC_CONTROL_3                   0x22
+#define WM8978_NOISE_GATE                      0x23
+#define WM8978_PLL_N                           0x24
+#define WM8978_PLL_K1                          0x25
+#define WM8978_PLL_K2                          0x26
+#define WM8978_PLL_K3                          0x27
+#define WM8978_3D_CONTROL                      0x29
+#define WM8978_BEEP_CONTROL                    0x2b
+#define WM8978_INPUT_CONTROL                   0x2c
+#define WM8978_LEFT_INP_PGA_CONTROL            0x2d
+#define WM8978_RIGHT_INP_PGA_CONTROL           0x2e
+#define WM8978_LEFT_ADC_BOOST_CONTROL          0x2f
+#define WM8978_RIGHT_ADC_BOOST_CONTROL         0x30
+#define WM8978_OUTPUT_CONTROL                  0x31
+#define WM8978_LEFT_MIXER_CONTROL              0x32
+#define WM8978_RIGHT_MIXER_CONTROL             0x33
+#define WM8978_LOUT1_HP_CONTROL                        0x34
+#define WM8978_ROUT1_HP_CONTROL                        0x35
+#define WM8978_LOUT2_SPK_CONTROL               0x36
+#define WM8978_ROUT2_SPK_CONTROL               0x37
+#define WM8978_OUT3_MIXER_CONTROL              0x38
+#define WM8978_OUT4_MIXER_CONTROL              0x39
+
+#define WM8978_CACHEREGNUM                     58
+
+/* Clock divider Id's */
+enum wm8978_clk_id {
+       WM8978_OPCLKRATE,
+       WM8978_BCLKDIV,
+};
+
+enum wm8978_sysclk_src {
+       WM8978_PLL,
+       WM8978_MCLK
+};
+
+extern struct snd_soc_dai wm8978_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8978;
+
+#endif /* __WM8978_H__ */
index 341481e0e83004c285bdaf634838647cfcc12a14..a54dc77b7f343f649b24ff58b9f401a6e8333235 100644 (file)
@@ -1319,10 +1319,6 @@ static int wm8990_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;
 
-       /* we only need to suspend if we are a valid card */
-       if (!codec->card)
-               return 0;
-
        wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
@@ -1335,10 +1331,6 @@ static int wm8990_resume(struct platform_device *pdev)
        u8 data[2];
        u16 *cache = codec->reg_cache;
 
-       /* we only need to resume if we are a valid card */
-       if (!codec->card)
-               return 0;
-
        /* Sync reg_cache with the hardware */
        for (i = 0; i < ARRAY_SIZE(wm8990_reg); i++) {
                if (i + 1 == WM8990_RESET)
index 2981afae842c9c48220410ac9c5e8d24cbbe2f5f..bf022f68b84f114ccc44835910df1315bca3fe70 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * wm8993.c -- WM8993 ALSA SoC audio driver
  *
- * Copyright 2009 Wolfson Microelectronics plc
+ * Copyright 2009, 2010 Wolfson Microelectronics plc
  *
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
@@ -16,6 +16,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
+#include <linux/regulator/consumer.h>
 #include <linux/spi/spi.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include "wm8993.h"
 #include "wm_hubs.h"
 
+#define WM8993_NUM_SUPPLIES 6
+static const char *wm8993_supply_names[WM8993_NUM_SUPPLIES] = {
+       "DCVDD",
+       "DBVDD",
+       "AVDD1",
+       "AVDD2",
+       "CPVDD",
+       "SPKVDD",
+};
+
 static u16 wm8993_reg_defaults[WM8993_REGISTER_COUNT] = {
        0x8993,     /* R0   - Software Reset */
        0x0000,     /* R1   - Power Management (1) */
@@ -213,7 +224,9 @@ static struct {
 };
 
 struct wm8993_priv {
+       struct wm_hubs_data hubs_data;
        u16 reg_cache[WM8993_REGISTER_COUNT];
+       struct regulator_bulk_data supplies[WM8993_NUM_SUPPLIES];
        struct wm8993_platform_data pdata;
        struct snd_soc_codec codec;
        int master;
@@ -227,36 +240,9 @@ struct wm8993_priv {
        int class_w_users;
        unsigned int fll_fref;
        unsigned int fll_fout;
+       int fll_src;
 };
 
-static unsigned int wm8993_read_hw(struct snd_soc_codec *codec, u8 reg)
-{
-       struct i2c_msg xfer[2];
-       u16 data;
-       int ret;
-       struct i2c_client *i2c = codec->control_data;
-
-       /* Write register */
-       xfer[0].addr = i2c->addr;
-       xfer[0].flags = 0;
-       xfer[0].len = 1;
-       xfer[0].buf = &reg;
-
-       /* Read data */
-       xfer[1].addr = i2c->addr;
-       xfer[1].flags = I2C_M_RD;
-       xfer[1].len = 2;
-       xfer[1].buf = (u8 *)&data;
-
-       ret = i2c_transfer(i2c->adapter, xfer, 2);
-       if (ret != 2) {
-               dev_err(codec->dev, "Failed to read 0x%x: %d\n", reg, ret);
-               return 0;
-       }
-
-       return (data >> 8) | ((data & 0xff) << 8);
-}
-
 static int wm8993_volatile(unsigned int reg)
 {
        switch (reg) {
@@ -271,48 +257,6 @@ static int wm8993_volatile(unsigned int reg)
        }
 }
 
-static unsigned int wm8993_read(struct snd_soc_codec *codec,
-                               unsigned int reg)
-{
-       u16 *reg_cache = codec->reg_cache;
-
-       BUG_ON(reg > WM8993_MAX_REGISTER);
-
-       if (wm8993_volatile(reg))
-               return wm8993_read_hw(codec, reg);
-       else
-               return reg_cache[reg];
-}
-
-static int wm8993_write(struct snd_soc_codec *codec, unsigned int reg,
-                       unsigned int value)
-{
-       u16 *reg_cache = codec->reg_cache;
-       u8 data[3];
-       int ret;
-
-       BUG_ON(reg > WM8993_MAX_REGISTER);
-
-       /* data is
-        *   D15..D9 WM8993 register offset
-        *   D8...D0 register data
-        */
-       data[0] = reg;
-       data[1] = value >> 8;
-       data[2] = value & 0x00ff;
-
-       if (!wm8993_volatile(reg))
-               reg_cache[reg] = value;
-
-       ret = codec->hw_write(codec->control_data, data, 3);
-
-       if (ret == 3)
-               return 0;
-       if (ret < 0)
-               return ret;
-       return -EIO;
-}
-
 struct _fll_div {
        u16 fll_fratio;
        u16 fll_outdiv;
@@ -441,9 +385,9 @@ static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
                wm8993->fll_fref = 0;
                wm8993->fll_fout = 0;
 
-               reg1 = wm8993_read(codec, WM8993_FLL_CONTROL_1);
+               reg1 = snd_soc_read(codec, WM8993_FLL_CONTROL_1);
                reg1 &= ~WM8993_FLL_ENA;
-               wm8993_write(codec, WM8993_FLL_CONTROL_1, reg1);
+               snd_soc_write(codec, WM8993_FLL_CONTROL_1, reg1);
 
                return 0;
        }
@@ -452,7 +396,7 @@ static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
        if (ret != 0)
                return ret;
 
-       reg5 = wm8993_read(codec, WM8993_FLL_CONTROL_5);
+       reg5 = snd_soc_read(codec, WM8993_FLL_CONTROL_5);
        reg5 &= ~WM8993_FLL_CLK_SRC_MASK;
 
        switch (fll_id) {
@@ -474,38 +418,39 @@ static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
 
        /* Any FLL configuration change requires that the FLL be
         * disabled first. */
-       reg1 = wm8993_read(codec, WM8993_FLL_CONTROL_1);
+       reg1 = snd_soc_read(codec, WM8993_FLL_CONTROL_1);
        reg1 &= ~WM8993_FLL_ENA;
-       wm8993_write(codec, WM8993_FLL_CONTROL_1, reg1);
+       snd_soc_write(codec, WM8993_FLL_CONTROL_1, reg1);
 
        /* Apply the configuration */
        if (fll_div.k)
                reg1 |= WM8993_FLL_FRAC_MASK;
        else
                reg1 &= ~WM8993_FLL_FRAC_MASK;
-       wm8993_write(codec, WM8993_FLL_CONTROL_1, reg1);
+       snd_soc_write(codec, WM8993_FLL_CONTROL_1, reg1);
 
-       wm8993_write(codec, WM8993_FLL_CONTROL_2,
-                    (fll_div.fll_outdiv << WM8993_FLL_OUTDIV_SHIFT) |
-                    (fll_div.fll_fratio << WM8993_FLL_FRATIO_SHIFT));
-       wm8993_write(codec, WM8993_FLL_CONTROL_3, fll_div.k);
+       snd_soc_write(codec, WM8993_FLL_CONTROL_2,
+                     (fll_div.fll_outdiv << WM8993_FLL_OUTDIV_SHIFT) |
+                     (fll_div.fll_fratio << WM8993_FLL_FRATIO_SHIFT));
+       snd_soc_write(codec, WM8993_FLL_CONTROL_3, fll_div.k);
 
-       reg4 = wm8993_read(codec, WM8993_FLL_CONTROL_4);
+       reg4 = snd_soc_read(codec, WM8993_FLL_CONTROL_4);
        reg4 &= ~WM8993_FLL_N_MASK;
        reg4 |= fll_div.n << WM8993_FLL_N_SHIFT;
-       wm8993_write(codec, WM8993_FLL_CONTROL_4, reg4);
+       snd_soc_write(codec, WM8993_FLL_CONTROL_4, reg4);
 
        reg5 &= ~WM8993_FLL_CLK_REF_DIV_MASK;
        reg5 |= fll_div.fll_clk_ref_div << WM8993_FLL_CLK_REF_DIV_SHIFT;
-       wm8993_write(codec, WM8993_FLL_CONTROL_5, reg5);
+       snd_soc_write(codec, WM8993_FLL_CONTROL_5, reg5);
 
        /* Enable the FLL */
-       wm8993_write(codec, WM8993_FLL_CONTROL_1, reg1 | WM8993_FLL_ENA);
+       snd_soc_write(codec, WM8993_FLL_CONTROL_1, reg1 | WM8993_FLL_ENA);
 
        dev_dbg(codec->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout);
 
        wm8993->fll_fref = Fref;
        wm8993->fll_fout = Fout;
+       wm8993->fll_src = source;
 
        return 0;
 }
@@ -520,7 +465,7 @@ static int configure_clock(struct snd_soc_codec *codec)
        case WM8993_SYSCLK_MCLK:
                dev_dbg(codec->dev, "Using %dHz MCLK\n", wm8993->mclk_rate);
 
-               reg = wm8993_read(codec, WM8993_CLOCKING_2);
+               reg = snd_soc_read(codec, WM8993_CLOCKING_2);
                reg &= ~(WM8993_MCLK_DIV | WM8993_SYSCLK_SRC);
                if (wm8993->mclk_rate > 13500000) {
                        reg |= WM8993_MCLK_DIV;
@@ -529,14 +474,14 @@ static int configure_clock(struct snd_soc_codec *codec)
                        reg &= ~WM8993_MCLK_DIV;
                        wm8993->sysclk_rate = wm8993->mclk_rate;
                }
-               wm8993_write(codec, WM8993_CLOCKING_2, reg);
+               snd_soc_write(codec, WM8993_CLOCKING_2, reg);
                break;
 
        case WM8993_SYSCLK_FLL:
                dev_dbg(codec->dev, "Using %dHz FLL clock\n",
                        wm8993->fll_fout);
 
-               reg = wm8993_read(codec, WM8993_CLOCKING_2);
+               reg = snd_soc_read(codec, WM8993_CLOCKING_2);
                reg |= WM8993_SYSCLK_SRC;
                if (wm8993->fll_fout > 13500000) {
                        reg |= WM8993_MCLK_DIV;
@@ -545,7 +490,7 @@ static int configure_clock(struct snd_soc_codec *codec)
                        reg &= ~WM8993_MCLK_DIV;
                        wm8993->sysclk_rate = wm8993->fll_fout;
                }
-               wm8993_write(codec, WM8993_CLOCKING_2, reg);
+               snd_soc_write(codec, WM8993_CLOCKING_2, reg);
                break;
 
        default:
@@ -978,10 +923,33 @@ static const struct snd_soc_dapm_route routes[] = {
        { "Right Headphone Mux", "DAC", "DACR" },
 };
 
+static void wm8993_cache_restore(struct snd_soc_codec *codec)
+{
+       u16 *cache = codec->reg_cache;
+       int i;
+
+       if (!codec->cache_sync)
+               return;
+
+       /* Reenable hardware writes */
+       codec->cache_only = 0;
+
+       /* Restore the register settings */
+       for (i = 1; i < WM8993_MAX_REGISTER; i++) {
+               if (cache[i] == wm8993_reg_defaults[i])
+                       continue;
+               snd_soc_write(codec, i, cache[i]);
+       }
+
+       /* We're in sync again */
+       codec->cache_sync = 0;
+}
+
 static int wm8993_set_bias_level(struct snd_soc_codec *codec,
                                 enum snd_soc_bias_level level)
 {
        struct wm8993_priv *wm8993 = codec->private_data;
+       int ret;
 
        switch (level) {
        case SND_SOC_BIAS_ON:
@@ -995,6 +963,18 @@ static int wm8993_set_bias_level(struct snd_soc_codec *codec,
 
        case SND_SOC_BIAS_STANDBY:
                if (codec->bias_level == SND_SOC_BIAS_OFF) {
+                       ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies),
+                                                   wm8993->supplies);
+                       if (ret != 0)
+                               return ret;
+
+                       wm8993_cache_restore(codec);
+
+                       /* Tune DC servo configuration */
+                       snd_soc_write(codec, 0x44, 3);
+                       snd_soc_write(codec, 0x56, 3);
+                       snd_soc_write(codec, 0x44, 0);
+
                        /* Bring up VMID with fast soft start */
                        snd_soc_update_bits(codec, WM8993_ANTIPOP2,
                                            WM8993_STARTUP_BIAS_ENA |
@@ -1042,6 +1022,18 @@ static int wm8993_set_bias_level(struct snd_soc_codec *codec,
                snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
                                    WM8993_VMID_SEL_MASK | WM8993_BIAS_ENA,
                                    0);
+
+#ifdef CONFIG_REGULATOR
+               /* Post 2.6.34 we will be able to get a callback when
+                * the regulators are disabled which we can use but
+               * for now just assume that the power will be cut if
+               * the regulator API is in use.
+               */
+               codec->cache_sync = 1;
+#endif
+
+               regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies),
+                                      wm8993->supplies);
                break;
        }
 
@@ -1075,8 +1067,8 @@ static int wm8993_set_dai_fmt(struct snd_soc_dai *dai,
 {
        struct snd_soc_codec *codec = dai->codec;
        struct wm8993_priv *wm8993 = codec->private_data;
-       unsigned int aif1 = wm8993_read(codec, WM8993_AUDIO_INTERFACE_1);
-       unsigned int aif4 = wm8993_read(codec, WM8993_AUDIO_INTERFACE_4);
+       unsigned int aif1 = snd_soc_read(codec, WM8993_AUDIO_INTERFACE_1);
+       unsigned int aif4 = snd_soc_read(codec, WM8993_AUDIO_INTERFACE_4);
 
        aif1 &= ~(WM8993_BCLK_DIR | WM8993_AIF_BCLK_INV |
                  WM8993_AIF_LRCLK_INV | WM8993_AIF_FMT_MASK);
@@ -1159,8 +1151,8 @@ static int wm8993_set_dai_fmt(struct snd_soc_dai *dai,
                return -EINVAL;
        }
 
-       wm8993_write(codec, WM8993_AUDIO_INTERFACE_1, aif1);
-       wm8993_write(codec, WM8993_AUDIO_INTERFACE_4, aif4);
+       snd_soc_write(codec, WM8993_AUDIO_INTERFACE_1, aif1);
+       snd_soc_write(codec, WM8993_AUDIO_INTERFACE_4, aif4);
 
        return 0;
 }
@@ -1174,16 +1166,16 @@ static int wm8993_hw_params(struct snd_pcm_substream *substream,
        int ret, i, best, best_val, cur_val;
        unsigned int clocking1, clocking3, aif1, aif4;
 
-       clocking1 = wm8993_read(codec, WM8993_CLOCKING_1);
+       clocking1 = snd_soc_read(codec, WM8993_CLOCKING_1);
        clocking1 &= ~WM8993_BCLK_DIV_MASK;
 
-       clocking3 = wm8993_read(codec, WM8993_CLOCKING_3);
+       clocking3 = snd_soc_read(codec, WM8993_CLOCKING_3);
        clocking3 &= ~(WM8993_CLK_SYS_RATE_MASK | WM8993_SAMPLE_RATE_MASK);
 
-       aif1 = wm8993_read(codec, WM8993_AUDIO_INTERFACE_1);
+       aif1 = snd_soc_read(codec, WM8993_AUDIO_INTERFACE_1);
        aif1 &= ~WM8993_AIF_WL_MASK;
 
-       aif4 = wm8993_read(codec, WM8993_AUDIO_INTERFACE_4);
+       aif4 = snd_soc_read(codec, WM8993_AUDIO_INTERFACE_4);
        aif4 &= ~WM8993_LRCLK_RATE_MASK;
 
        /* What BCLK do we need? */
@@ -1276,14 +1268,14 @@ static int wm8993_hw_params(struct snd_pcm_substream *substream,
        dev_dbg(codec->dev, "LRCLK_RATE is %d\n", wm8993->bclk / wm8993->fs);
        aif4 |= wm8993->bclk / wm8993->fs;
 
-       wm8993_write(codec, WM8993_CLOCKING_1, clocking1);
-       wm8993_write(codec, WM8993_CLOCKING_3, clocking3);
-       wm8993_write(codec, WM8993_AUDIO_INTERFACE_1, aif1);
-       wm8993_write(codec, WM8993_AUDIO_INTERFACE_4, aif4);
+       snd_soc_write(codec, WM8993_CLOCKING_1, clocking1);
+       snd_soc_write(codec, WM8993_CLOCKING_3, clocking3);
+       snd_soc_write(codec, WM8993_AUDIO_INTERFACE_1, aif1);
+       snd_soc_write(codec, WM8993_AUDIO_INTERFACE_4, aif4);
 
        /* ReTune Mobile? */
        if (wm8993->pdata.num_retune_configs) {
-               u16 eq1 = wm8993_read(codec, WM8993_EQ1);
+               u16 eq1 = snd_soc_read(codec, WM8993_EQ1);
                struct wm8993_retune_mobile_setting *s;
 
                best = 0;
@@ -1306,7 +1298,7 @@ static int wm8993_hw_params(struct snd_pcm_substream *substream,
                snd_soc_update_bits(codec, WM8993_EQ1, WM8993_EQ_ENA, 0);
 
                for (i = 1; i < ARRAY_SIZE(s->config); i++)
-                       wm8993_write(codec, WM8993_EQ1 + i, s->config[i]);
+                       snd_soc_write(codec, WM8993_EQ1 + i, s->config[i]);
 
                snd_soc_update_bits(codec, WM8993_EQ1, WM8993_EQ_ENA, eq1);
        }
@@ -1319,14 +1311,14 @@ static int wm8993_digital_mute(struct snd_soc_dai *codec_dai, int mute)
        struct snd_soc_codec *codec = codec_dai->codec;
        unsigned int reg;
 
-       reg = wm8993_read(codec, WM8993_DAC_CTRL);
+       reg = snd_soc_read(codec, WM8993_DAC_CTRL);
 
        if (mute)
                reg |= WM8993_DAC_MUTE;
        else
                reg &= ~WM8993_DAC_MUTE;
 
-       wm8993_write(codec, WM8993_DAC_CTRL, reg);
+       snd_soc_write(codec, WM8993_DAC_CTRL, reg);
 
        return 0;
 }
@@ -1480,9 +1472,66 @@ static int wm8993_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int wm8993_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;
+       struct wm8993_priv *wm8993 = codec->private_data;
+       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);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "Failed to stop FLL\n");
+               return ret;
+       }
+
+       wm8993->fll_fout = fll_fout;
+       wm8993->fll_fref = fll_fref;
+
+       wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       return 0;
+}
+
+static int wm8993_resume(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->card->codec;
+       struct wm8993_priv *wm8993 = codec->private_data;
+       int ret;
+
+       wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       /* Restart the FLL? */
+       if (wm8993->fll_fout) {
+               int fll_fout = wm8993->fll_fout;
+               int fll_fref  = wm8993->fll_fref;
+
+               wm8993->fll_fref = 0;
+               wm8993->fll_fout = 0;
+
+               ret = wm8993_set_fll(codec->dai, 0, wm8993->fll_src,
+                                    fll_fref, fll_fout);
+               if (ret != 0)
+                       dev_err(codec->dev, "Failed to restart FLL\n");
+       }
+
+       return 0;
+}
+#else
+#define wm8993_suspend NULL
+#define wm8993_resume NULL
+#endif
+
 struct snd_soc_codec_device soc_codec_dev_wm8993 = {
        .probe =        wm8993_probe,
        .remove =       wm8993_remove,
+       .suspend =      wm8993_suspend,
+       .resume =       wm8993_resume,
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_wm8993);
 
@@ -1493,6 +1542,7 @@ static int wm8993_i2c_probe(struct i2c_client *i2c,
        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");
@@ -1513,9 +1563,7 @@ static int wm8993_i2c_probe(struct i2c_client *i2c,
        INIT_LIST_HEAD(&codec->dapm_paths);
 
        codec->name = "WM8993";
-       codec->read = wm8993_read;
-       codec->write = wm8993_write;
-       codec->hw_write = (hw_write_t)i2c_master_send;
+       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;
@@ -1524,25 +1572,53 @@ static int wm8993_i2c_probe(struct i2c_client *i2c,
        codec->num_dai = 1;
        codec->private_data = 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;
 
-       val = wm8993_read_hw(codec, WM8993_SOFTWARE_RESET);
+       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;
+               goto err_enable;
        }
 
-       ret = wm8993_write(codec, WM8993_SOFTWARE_RESET, 0xffff);
+       ret = snd_soc_write(codec, WM8993_SOFTWARE_RESET, 0xffff);
        if (ret != 0)
-               goto err;
+               goto err_enable;
+
+       codec->cache_only = 1;
 
        /* By default we're using the output mixers */
        wm8993->class_w_users = 2;
@@ -1572,7 +1648,7 @@ static int wm8993_i2c_probe(struct i2c_client *i2c,
                             
        ret = wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        if (ret != 0)
-               goto err;
+               goto err_enable;
 
        wm8993_dai.dev = codec->dev;
 
@@ -1586,6 +1662,10 @@ static int wm8993_i2c_probe(struct i2c_client *i2c,
 
 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);
@@ -1600,6 +1680,7 @@ static int wm8993_i2c_remove(struct i2c_client *client)
        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);
 
        return 0;
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
new file mode 100644 (file)
index 0000000..29f3771
--- /dev/null
@@ -0,0 +1,3867 @@
+/*
+ * wm8994.c  --  WM8994 ALSA SoC Audio driver
+ *
+ * Copyright 2009 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/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.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/mfd/wm8994/core.h>
+#include <linux/mfd/wm8994/registers.h>
+#include <linux/mfd/wm8994/pdata.h>
+#include <linux/mfd/wm8994/gpio.h>
+
+#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;
+       int out;
+};
+
+#define WM8994_NUM_DRC 3
+#define WM8994_NUM_EQ  3
+
+static int wm8994_drc_base[] = {
+       WM8994_AIF1_DRC1_1,
+       WM8994_AIF1_DRC2_1,
+       WM8994_AIF2_DRC_1,
+};
+
+static int wm8994_retune_mobile_base[] = {
+       WM8994_AIF1_DAC1_EQ_GAINS_1,
+       WM8994_AIF1_DAC2_EQ_GAINS_1,
+       WM8994_AIF2_EQ_GAINS_1,
+};
+
+#define WM8994_REG_CACHE_SIZE  0x621
+
+/* codec private data */
+struct wm8994_priv {
+       struct wm_hubs_data hubs;
+       struct snd_soc_codec codec;
+       u16 reg_cache[WM8994_REG_CACHE_SIZE + 1];
+       int sysclk[2];
+       int sysclk_rate[2];
+       int mclk[2];
+       int aifclk[2];
+       struct fll_config fll[2], fll_suspend[2];
+
+       int dac_rates[2];
+       int lrclk_shared[2];
+
+       /* Platform dependant DRC configuration */
+       const char **drc_texts;
+       int drc_cfg[WM8994_NUM_DRC];
+       struct soc_enum drc_enum;
+
+       /* Platform dependant ReTune mobile configuration */
+       int num_retune_mobile_texts;
+       const char **retune_mobile_texts;
+       int retune_mobile_cfg[WM8994_NUM_EQ];
+       struct soc_enum retune_mobile_enum;
+
+       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 */
+} 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 */
+};
+
+static int wm8994_readable(unsigned int reg)
+{
+       if (reg >= ARRAY_SIZE(access_masks))
+               return 0;
+       return access_masks[reg].readable != 0;
+}
+
+static int wm8994_volatile(unsigned int reg)
+{
+       if (reg >= WM8994_REG_CACHE_SIZE)
+               return 1;
+
+       switch (reg) {
+       case WM8994_SOFTWARE_RESET:
+       case WM8994_CHIP_REVISION:
+       case WM8994_DC_SERVO_1:
+       case WM8994_DC_SERVO_READBACK:
+       case WM8994_RATE_STATUS:
+       case WM8994_LDO_1:
+       case WM8994_LDO_2:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static int wm8994_write(struct snd_soc_codec *codec, unsigned int reg,
+       unsigned int value)
+{
+       struct wm8994_priv *wm8994 = codec->private_data;
+
+       BUG_ON(reg > WM8994_MAX_REGISTER);
+
+       if (!wm8994_volatile(reg))
+               wm8994->reg_cache[reg] = value;
+
+       return wm8994_reg_write(codec->control_data, reg, value);
+}
+
+static unsigned int wm8994_read(struct snd_soc_codec *codec,
+                               unsigned int reg)
+{
+       u16 *reg_cache = codec->reg_cache;
+
+       BUG_ON(reg > WM8994_MAX_REGISTER);
+
+       if (wm8994_volatile(reg))
+               return wm8994_reg_read(codec->control_data, reg);
+       else
+               return reg_cache[reg];
+}
+
+static int configure_aif_clock(struct snd_soc_codec *codec, int aif)
+{
+       struct wm8994_priv *wm8994 = codec->private_data;
+       int rate;
+       int reg1 = 0;
+       int offset;
+
+       if (aif)
+               offset = 4;
+       else
+               offset = 0;
+
+       switch (wm8994->sysclk[aif]) {
+       case WM8994_SYSCLK_MCLK1:
+               rate = wm8994->mclk[0];
+               break;
+
+       case WM8994_SYSCLK_MCLK2:
+               reg1 |= 0x8;
+               rate = wm8994->mclk[1];
+               break;
+
+       case WM8994_SYSCLK_FLL1:
+               reg1 |= 0x10;
+               rate = wm8994->fll[0].out;
+               break;
+
+       case WM8994_SYSCLK_FLL2:
+               reg1 |= 0x18;
+               rate = wm8994->fll[1].out;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       if (rate >= 13500000) {
+               rate /= 2;
+               reg1 |= WM8994_AIF1CLK_DIV;
+
+               dev_dbg(codec->dev, "Dividing AIF%d clock to %dHz\n",
+                       aif + 1, rate);
+       }
+       wm8994->aifclk[aif] = rate;
+
+       snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1 + offset,
+                           WM8994_AIF1CLK_SRC_MASK | WM8994_AIF1CLK_DIV,
+                           reg1);
+
+       return 0;
+}
+
+static int configure_clock(struct snd_soc_codec *codec)
+{
+       struct wm8994_priv *wm8994 = codec->private_data;
+       int old, new;
+
+       /* Bring up the AIF clocks first */
+       configure_aif_clock(codec, 0);
+       configure_aif_clock(codec, 1);
+
+       /* Then switch CLK_SYS over to the higher of them; a change
+        * can only happen as a result of a clocking change which can
+        * only be made outside of DAPM so we can safely redo the
+        * clocking.
+        */
+
+       /* If they're equal it doesn't matter which is used */
+       if (wm8994->aifclk[0] == wm8994->aifclk[1])
+               return 0;
+
+       if (wm8994->aifclk[0] < wm8994->aifclk[1])
+               new = WM8994_SYSCLK_SRC;
+       else
+               new = 0;
+
+       old = snd_soc_read(codec, WM8994_CLOCKING_1) & WM8994_SYSCLK_SRC;
+
+       /* If there's no change then we're done. */
+       if (old == new)
+               return 0;
+
+       snd_soc_update_bits(codec, WM8994_CLOCKING_1, WM8994_SYSCLK_SRC, new);
+
+       snd_soc_dapm_sync(codec);
+
+       return 0;
+}
+
+static int check_clk_sys(struct snd_soc_dapm_widget *source,
+                        struct snd_soc_dapm_widget *sink)
+{
+       int reg = snd_soc_read(source->codec, WM8994_CLOCKING_1);
+       const char *clk;
+
+       /* Check what we're currently using for CLK_SYS */
+       if (reg & WM8994_SYSCLK_SRC)
+               clk = "AIF2CLK";
+       else
+               clk = "AIF1CLK";
+
+       return strcmp(source->name, clk) == 0;
+}
+
+static const char *sidetone_hpf_text[] = {
+       "2.7kHz", "1.35kHz", "675Hz", "370Hz", "180Hz", "90Hz", "45Hz"
+};
+
+static const struct soc_enum sidetone_hpf =
+       SOC_ENUM_SINGLE(WM8994_SIDETONE, 7, 7, sidetone_hpf_text);
+
+static const DECLARE_TLV_DB_SCALE(aif_tlv, 0, 600, 0);
+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(wm8994_3d_tlv, -1600, 183, 0);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+
+#define WM8994_DRC_SWITCH(xname, reg, shift) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
+       .put = wm8994_put_drc_sw, \
+       .private_value =  SOC_SINGLE_VALUE(reg, shift, 1, 0) }
+
+static int wm8994_put_drc_sw(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);
+       int mask, ret;
+
+       /* Can't enable both ADC and DAC paths simultaneously */
+       if (mc->shift == WM8994_AIF1DAC1_DRC_ENA_SHIFT)
+               mask = WM8994_AIF1ADC1L_DRC_ENA_MASK |
+                       WM8994_AIF1ADC1R_DRC_ENA_MASK;
+       else
+               mask = WM8994_AIF1DAC1_DRC_ENA_MASK;
+
+       ret = snd_soc_read(codec, mc->reg);
+       if (ret < 0)
+               return ret;
+       if (ret & mask)
+               return -EINVAL;
+
+       return snd_soc_put_volsw(kcontrol, ucontrol);
+}
+
+
+
+static void wm8994_set_drc(struct snd_soc_codec *codec, int drc)
+{
+       struct wm8994_priv *wm8994 = codec->private_data;
+       struct wm8994_pdata *pdata = wm8994->pdata;
+       int base = wm8994_drc_base[drc];
+       int cfg = wm8994->drc_cfg[drc];
+       int save, i;
+
+       /* Save any enables; the configuration should clear them. */
+       save = snd_soc_read(codec, base);
+       save &= WM8994_AIF1DAC1_DRC_ENA | WM8994_AIF1ADC1L_DRC_ENA |
+               WM8994_AIF1ADC1R_DRC_ENA;
+
+       for (i = 0; i < WM8994_DRC_REGS; i++)
+               snd_soc_update_bits(codec, base + i, 0xffff,
+                                   pdata->drc_cfgs[cfg].regs[i]);
+
+       snd_soc_update_bits(codec, base, WM8994_AIF1DAC1_DRC_ENA |
+                            WM8994_AIF1ADC1L_DRC_ENA |
+                            WM8994_AIF1ADC1R_DRC_ENA, save);
+}
+
+/* Icky as hell but saves code duplication */
+static int wm8994_get_drc(const char *name)
+{
+       if (strcmp(name, "AIF1DRC1 Mode") == 0)
+               return 0;
+       if (strcmp(name, "AIF1DRC2 Mode") == 0)
+               return 1;
+       if (strcmp(name, "AIF2DRC Mode") == 0)
+               return 2;
+       return -EINVAL;
+}
+
+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 = codec->private_data;       
+       struct wm8994_pdata *pdata = wm8994->pdata;
+       int drc = wm8994_get_drc(kcontrol->id.name);
+       int value = ucontrol->value.integer.value[0];
+
+       if (drc < 0)
+               return drc;
+
+       if (value >= pdata->num_drc_cfgs)
+               return -EINVAL;
+
+       wm8994->drc_cfg[drc] = value;
+
+       wm8994_set_drc(codec, drc);
+
+       return 0;
+}
+
+static int wm8994_get_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 = codec->private_data;
+       int drc = wm8994_get_drc(kcontrol->id.name);
+
+       ucontrol->value.enumerated.item[0] = wm8994->drc_cfg[drc];
+
+       return 0;
+}
+
+static void wm8994_set_retune_mobile(struct snd_soc_codec *codec, int block)
+{
+       struct wm8994_priv *wm8994 = codec->private_data;
+       struct wm8994_pdata *pdata = wm8994->pdata;
+       int base = wm8994_retune_mobile_base[block];
+       int iface, best, best_val, save, i, cfg;
+
+       if (!pdata || !wm8994->num_retune_mobile_texts)
+               return;
+
+       switch (block) {
+       case 0:
+       case 1:
+               iface = 0;
+               break;
+       case 2:
+               iface = 1;
+               break;
+       default:
+               return;
+       }
+
+       /* Find the version of the currently selected configuration
+        * with the nearest sample rate. */
+       cfg = wm8994->retune_mobile_cfg[block];
+       best = 0;
+       best_val = INT_MAX;
+       for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) {
+               if (strcmp(pdata->retune_mobile_cfgs[i].name,
+                          wm8994->retune_mobile_texts[cfg]) == 0 &&
+                   abs(pdata->retune_mobile_cfgs[i].rate
+                       - wm8994->dac_rates[iface]) < best_val) {
+                       best = i;
+                       best_val = abs(pdata->retune_mobile_cfgs[i].rate
+                                      - wm8994->dac_rates[iface]);
+               }
+       }
+
+       dev_dbg(codec->dev, "ReTune Mobile %d %s/%dHz for %dHz sample rate\n",
+               block,
+               pdata->retune_mobile_cfgs[best].name,
+               pdata->retune_mobile_cfgs[best].rate,
+               wm8994->dac_rates[iface]);
+
+       /* The EQ will be disabled while reconfiguring it, remember the
+        * current configuration. 
+        */
+       save = snd_soc_read(codec, base);
+       save &= WM8994_AIF1DAC1_EQ_ENA;
+
+       for (i = 0; i < WM8994_EQ_REGS; i++)
+               snd_soc_update_bits(codec, base + i, 0xffff,
+                               pdata->retune_mobile_cfgs[best].regs[i]);
+
+       snd_soc_update_bits(codec, base, WM8994_AIF1DAC1_EQ_ENA, save);
+}
+
+/* Icky as hell but saves code duplication */
+static int wm8994_get_retune_mobile_block(const char *name)
+{
+       if (strcmp(name, "AIF1.1 EQ Mode") == 0)
+               return 0;
+       if (strcmp(name, "AIF1.2 EQ Mode") == 0)
+               return 1;
+       if (strcmp(name, "AIF2 EQ Mode") == 0)
+               return 2;
+       return -EINVAL;
+}
+
+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 = codec->private_data;       
+       struct wm8994_pdata *pdata = wm8994->pdata;
+       int block = wm8994_get_retune_mobile_block(kcontrol->id.name);
+       int value = ucontrol->value.integer.value[0];
+
+       if (block < 0)
+               return block;
+
+       if (value >= pdata->num_retune_mobile_cfgs)
+               return -EINVAL;
+
+       wm8994->retune_mobile_cfg[block] = value;
+
+       wm8994_set_retune_mobile(codec, block);
+
+       return 0;
+}
+
+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 = codec->private_data;
+       int block = wm8994_get_retune_mobile_block(kcontrol->id.name);
+
+       ucontrol->value.enumerated.item[0] = wm8994->retune_mobile_cfg[block];
+
+       return 0;
+}
+
+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,
+                1, 119, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("AIF1ADC2 Volume", WM8994_AIF1_ADC2_LEFT_VOLUME,
+                WM8994_AIF1_ADC2_RIGHT_VOLUME,
+                1, 119, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("AIF2ADC Volume", WM8994_AIF2_ADC_LEFT_VOLUME,
+                WM8994_AIF2_ADC_RIGHT_VOLUME,
+                1, 119, 0, digital_tlv),
+
+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,
+                WM8994_AIF1_DAC2_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("AIF2DAC Volume", WM8994_AIF2_DAC_LEFT_VOLUME,
+                WM8994_AIF2_DAC_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
+
+SOC_SINGLE_TLV("AIF1 Boost Volume", WM8994_AIF1_CONTROL_2, 10, 3, 0, aif_tlv),
+SOC_SINGLE_TLV("AIF2 Boost Volume", WM8994_AIF2_CONTROL_2, 10, 3, 0, aif_tlv),
+
+SOC_SINGLE("AIF1DAC1 EQ Switch", WM8994_AIF1_DAC1_EQ_GAINS_1, 0, 1, 0),
+SOC_SINGLE("AIF1DAC2 EQ Switch", WM8994_AIF1_DAC2_EQ_GAINS_1, 0, 1, 0),
+SOC_SINGLE("AIF2 EQ Switch", WM8994_AIF2_EQ_GAINS_1, 0, 1, 0),
+
+WM8994_DRC_SWITCH("AIF1DAC1 DRC Switch", WM8994_AIF1_DRC1_1, 2),
+WM8994_DRC_SWITCH("AIF1ADC1L DRC Switch", WM8994_AIF1_DRC1_1, 1),
+WM8994_DRC_SWITCH("AIF1ADC1R DRC Switch", WM8994_AIF1_DRC1_1, 0),
+
+WM8994_DRC_SWITCH("AIF1DAC2 DRC Switch", WM8994_AIF1_DRC2_1, 2),
+WM8994_DRC_SWITCH("AIF1ADC2L DRC Switch", WM8994_AIF1_DRC2_1, 1),
+WM8994_DRC_SWITCH("AIF1ADC2R DRC Switch", WM8994_AIF1_DRC2_1, 0),
+
+WM8994_DRC_SWITCH("AIF2DAC DRC Switch", WM8994_AIF2_DRC_1, 2),
+WM8994_DRC_SWITCH("AIF2ADCL DRC Switch", WM8994_AIF2_DRC_1, 1),
+WM8994_DRC_SWITCH("AIF2ADCR DRC Switch", WM8994_AIF2_DRC_1, 0),
+
+SOC_SINGLE_TLV("DAC1 Right Sidetone Volume", WM8994_DAC1_MIXER_VOLUMES,
+              5, 12, 0, st_tlv),
+SOC_SINGLE_TLV("DAC1 Left Sidetone Volume", WM8994_DAC1_MIXER_VOLUMES,
+              0, 12, 0, st_tlv),
+SOC_SINGLE_TLV("DAC2 Right Sidetone Volume", WM8994_DAC2_MIXER_VOLUMES,
+              5, 12, 0, st_tlv),
+SOC_SINGLE_TLV("DAC2 Left Sidetone Volume", WM8994_DAC2_MIXER_VOLUMES,
+              0, 12, 0, st_tlv),
+SOC_ENUM("Sidetone HPF Mux", sidetone_hpf),
+SOC_SINGLE("Sidetone HPF Switch", WM8994_SIDETONE, 6, 1, 0),
+
+SOC_DOUBLE_R_TLV("DAC1 Volume", WM8994_DAC1_LEFT_VOLUME,
+                WM8994_DAC1_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
+SOC_DOUBLE_R("DAC1 Switch", WM8994_DAC1_LEFT_VOLUME,
+            WM8994_DAC1_RIGHT_VOLUME, 9, 1, 1),
+
+SOC_DOUBLE_R_TLV("DAC2 Volume", WM8994_DAC2_LEFT_VOLUME,
+                WM8994_DAC2_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
+SOC_DOUBLE_R("DAC2 Switch", WM8994_DAC2_LEFT_VOLUME,
+            WM8994_DAC2_RIGHT_VOLUME, 9, 1, 1),
+
+SOC_SINGLE_TLV("SPKL DAC2 Volume", WM8994_SPKMIXL_ATTENUATION,
+              6, 1, 1, wm_hubs_spkmix_tlv),
+SOC_SINGLE_TLV("SPKL DAC1 Volume", WM8994_SPKMIXL_ATTENUATION,
+              2, 1, 1, wm_hubs_spkmix_tlv),
+
+SOC_SINGLE_TLV("SPKR DAC2 Volume", WM8994_SPKMIXR_ATTENUATION,
+              6, 1, 1, wm_hubs_spkmix_tlv),
+SOC_SINGLE_TLV("SPKR DAC1 Volume", WM8994_SPKMIXR_ATTENUATION,
+              2, 1, 1, wm_hubs_spkmix_tlv),
+
+SOC_SINGLE_TLV("AIF1DAC1 3D Stereo Volume", WM8994_AIF1_DAC1_FILTERS_2,
+              10, 15, 0, wm8994_3d_tlv),
+SOC_SINGLE("AIF1DAC1 3D Stereo Switch", WM8994_AIF1_DAC2_FILTERS_2,
+          8, 1, 0),
+SOC_SINGLE_TLV("AIF1DAC2 3D Stereo Volume", WM8994_AIF1_DAC2_FILTERS_2,
+              10, 15, 0, wm8994_3d_tlv),
+SOC_SINGLE("AIF1DAC2 3D Stereo Switch", WM8994_AIF1_DAC2_FILTERS_2,
+          8, 1, 0),
+SOC_SINGLE_TLV("AIF2DAC 3D Stereo Volume", WM8994_AIF1_DAC1_FILTERS_2,
+              10, 15, 0, wm8994_3d_tlv),
+SOC_SINGLE("AIF2DAC 3D Stereo Switch", WM8994_AIF1_DAC2_FILTERS_2,
+          8, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8994_eq_controls[] = {
+SOC_SINGLE_TLV("AIF1DAC1 EQ1 Volume", WM8994_AIF1_DAC1_EQ_GAINS_1, 11, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("AIF1DAC1 EQ2 Volume", WM8994_AIF1_DAC1_EQ_GAINS_1, 6, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("AIF1DAC1 EQ3 Volume", WM8994_AIF1_DAC1_EQ_GAINS_1, 1, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("AIF1DAC1 EQ4 Volume", WM8994_AIF1_DAC1_EQ_GAINS_2, 11, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("AIF1DAC1 EQ5 Volume", WM8994_AIF1_DAC1_EQ_GAINS_2, 6, 31, 0,
+              eq_tlv),
+
+SOC_SINGLE_TLV("AIF1DAC2 EQ1 Volume", WM8994_AIF1_DAC2_EQ_GAINS_1, 11, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("AIF1DAC2 EQ2 Volume", WM8994_AIF1_DAC2_EQ_GAINS_1, 6, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("AIF1DAC2 EQ3 Volume", WM8994_AIF1_DAC2_EQ_GAINS_1, 1, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("AIF1DAC2 EQ4 Volume", WM8994_AIF1_DAC2_EQ_GAINS_2, 11, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("AIF1DAC2 EQ5 Volume", WM8994_AIF1_DAC2_EQ_GAINS_2, 6, 31, 0,
+              eq_tlv),
+
+SOC_SINGLE_TLV("AIF2 EQ1 Volume", WM8994_AIF2_EQ_GAINS_1, 11, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("AIF2 EQ2 Volume", WM8994_AIF2_EQ_GAINS_1, 6, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("AIF2 EQ3 Volume", WM8994_AIF2_EQ_GAINS_1, 1, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("AIF2 EQ4 Volume", WM8994_AIF2_EQ_GAINS_2, 11, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("AIF2 EQ5 Volume", WM8994_AIF2_EQ_GAINS_2, 6, 31, 0,
+              eq_tlv),
+};
+
+static int clk_sys_event(struct snd_soc_dapm_widget *w,
+                        struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               return configure_clock(codec);
+
+       case SND_SOC_DAPM_POST_PMD:
+               configure_clock(codec);
+               break;
+       }
+
+       return 0;
+}
+
+static void wm8994_update_class_w(struct snd_soc_codec *codec)
+{
+       int enable = 1;
+       int source = 0;  /* GCC flow analysis can't track enable */
+       int reg, reg_r;
+
+       /* Only support direct DAC->headphone paths */
+       reg = snd_soc_read(codec, WM8994_OUTPUT_MIXER_1);
+       if (!(reg & WM8994_DAC1L_TO_HPOUT1L)) {
+               dev_dbg(codec->dev, "HPL connected to output mixer\n");
+               enable = 0;
+       }
+
+       reg = snd_soc_read(codec, WM8994_OUTPUT_MIXER_2);
+       if (!(reg & WM8994_DAC1R_TO_HPOUT1R)) {
+               dev_dbg(codec->dev, "HPR connected to output mixer\n");
+               enable = 0;
+       }
+
+       /* We also need the same setting for L/R and only one path */
+       reg = snd_soc_read(codec, WM8994_DAC1_LEFT_MIXER_ROUTING);
+       switch (reg) {
+       case WM8994_AIF2DACL_TO_DAC1L:
+               dev_dbg(codec->dev, "Class W source AIF2DAC\n");
+               source = 2 << WM8994_CP_DYN_SRC_SEL_SHIFT;
+               break;
+       case WM8994_AIF1DAC2L_TO_DAC1L:
+               dev_dbg(codec->dev, "Class W source AIF1DAC2\n");
+               source = 1 << WM8994_CP_DYN_SRC_SEL_SHIFT;
+               break;
+       case WM8994_AIF1DAC1L_TO_DAC1L:
+               dev_dbg(codec->dev, "Class W source AIF1DAC1\n");
+               source = 0 << WM8994_CP_DYN_SRC_SEL_SHIFT;
+               break;
+       default:
+               dev_dbg(codec->dev, "DAC mixer setting: %x\n", reg);
+               enable = 0;
+               break;
+       }
+
+       reg_r = snd_soc_read(codec, WM8994_DAC1_RIGHT_MIXER_ROUTING);
+       if (reg_r != reg) {
+               dev_dbg(codec->dev, "Left and right DAC mixers different\n");
+               enable = 0;
+       }
+
+       if (enable) {
+               dev_dbg(codec->dev, "Class W enabled\n");
+               snd_soc_update_bits(codec, WM8994_CLASS_W_1,
+                                   WM8994_CP_DYN_PWR |
+                                   WM8994_CP_DYN_SRC_SEL_MASK,
+                                   source | WM8994_CP_DYN_PWR);
+               
+       } else {
+               dev_dbg(codec->dev, "Class W disabled\n");
+               snd_soc_update_bits(codec, WM8994_CLASS_W_1,
+                                   WM8994_CP_DYN_PWR, 0);
+       }
+}
+
+static const char *hp_mux_text[] = {
+       "Mixer",
+       "DAC",
+};
+
+#define WM8994_HP_ENUM(xname, xenum) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = snd_soc_info_enum_double, \
+       .get = snd_soc_dapm_get_enum_double, \
+       .put = wm8994_put_hp_enum, \
+       .private_value = (unsigned long)&xenum }
+
+static int wm8994_put_hp_enum(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = w->codec;
+       int ret;
+
+       ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+
+       wm8994_update_class_w(codec);
+
+       return ret;
+}
+
+static const struct soc_enum hpl_enum =
+       SOC_ENUM_SINGLE(WM8994_OUTPUT_MIXER_1, 8, 2, hp_mux_text);
+
+static const struct snd_kcontrol_new hpl_mux =
+       WM8994_HP_ENUM("Left Headphone Mux", hpl_enum);
+
+static const struct soc_enum hpr_enum =
+       SOC_ENUM_SINGLE(WM8994_OUTPUT_MIXER_2, 8, 2, hp_mux_text);
+
+static const struct snd_kcontrol_new hpr_mux =
+       WM8994_HP_ENUM("Right Headphone Mux", hpr_enum);
+
+static const char *adc_mux_text[] = {
+       "ADC",
+       "DMIC",
+};
+
+static const struct soc_enum adc_enum =
+       SOC_ENUM_SINGLE(0, 0, 2, adc_mux_text);
+
+static const struct snd_kcontrol_new adcl_mux =
+       SOC_DAPM_ENUM_VIRT("ADCL Mux", adc_enum);
+
+static const struct snd_kcontrol_new adcr_mux =
+       SOC_DAPM_ENUM_VIRT("ADCR Mux", adc_enum);
+
+static const struct snd_kcontrol_new left_speaker_mixer[] = {
+SOC_DAPM_SINGLE("DAC2 Switch", WM8994_SPEAKER_MIXER, 9, 1, 0),
+SOC_DAPM_SINGLE("Input Switch", WM8994_SPEAKER_MIXER, 7, 1, 0),
+SOC_DAPM_SINGLE("IN1LP Switch", WM8994_SPEAKER_MIXER, 5, 1, 0),
+SOC_DAPM_SINGLE("Output Switch", WM8994_SPEAKER_MIXER, 3, 1, 0),
+SOC_DAPM_SINGLE("DAC1 Switch", WM8994_SPEAKER_MIXER, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_speaker_mixer[] = {
+SOC_DAPM_SINGLE("DAC2 Switch", WM8994_SPEAKER_MIXER, 8, 1, 0),
+SOC_DAPM_SINGLE("Input Switch", WM8994_SPEAKER_MIXER, 6, 1, 0),
+SOC_DAPM_SINGLE("IN1RP Switch", WM8994_SPEAKER_MIXER, 4, 1, 0),
+SOC_DAPM_SINGLE("Output Switch", WM8994_SPEAKER_MIXER, 2, 1, 0),
+SOC_DAPM_SINGLE("DAC1 Switch", WM8994_SPEAKER_MIXER, 0, 1, 0),
+};
+
+/* Debugging; dump chip status after DAPM transitions */
+static int post_ev(struct snd_soc_dapm_widget *w,
+           struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       dev_dbg(codec->dev, "SRC status: %x\n",
+               snd_soc_read(codec,
+                            WM8994_RATE_STATUS));
+       return 0;
+}
+
+static const struct snd_kcontrol_new aif1adc1l_mix[] = {
+SOC_DAPM_SINGLE("ADC/DMIC Switch", WM8994_AIF1_ADC1_LEFT_MIXER_ROUTING,
+               1, 1, 0),
+SOC_DAPM_SINGLE("AIF2 Switch", WM8994_AIF1_ADC1_LEFT_MIXER_ROUTING,
+               0, 1, 0),
+};
+
+static const struct snd_kcontrol_new aif1adc1r_mix[] = {
+SOC_DAPM_SINGLE("ADC/DMIC Switch", WM8994_AIF1_ADC1_RIGHT_MIXER_ROUTING,
+               1, 1, 0),
+SOC_DAPM_SINGLE("AIF2 Switch", WM8994_AIF1_ADC1_RIGHT_MIXER_ROUTING,
+               0, 1, 0),
+};
+
+static const struct snd_kcontrol_new aif2dac2l_mix[] = {
+SOC_DAPM_SINGLE("Right Sidetone Switch", WM8994_DAC2_LEFT_MIXER_ROUTING,
+               5, 1, 0),
+SOC_DAPM_SINGLE("Left Sidetone Switch", WM8994_DAC2_LEFT_MIXER_ROUTING,
+               4, 1, 0),
+SOC_DAPM_SINGLE("AIF2 Switch", WM8994_DAC2_LEFT_MIXER_ROUTING,
+               2, 1, 0),
+SOC_DAPM_SINGLE("AIF1.2 Switch", WM8994_DAC2_LEFT_MIXER_ROUTING,
+               1, 1, 0),
+SOC_DAPM_SINGLE("AIF1.1 Switch", WM8994_DAC2_LEFT_MIXER_ROUTING,
+               0, 1, 0),
+};
+
+static const struct snd_kcontrol_new aif2dac2r_mix[] = {
+SOC_DAPM_SINGLE("Right Sidetone Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING,
+               5, 1, 0),
+SOC_DAPM_SINGLE("Left Sidetone Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING,
+               4, 1, 0),
+SOC_DAPM_SINGLE("AIF2 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING,
+               2, 1, 0),
+SOC_DAPM_SINGLE("AIF1.2 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING,
+               1, 1, 0),
+SOC_DAPM_SINGLE("AIF1.1 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING,
+               0, 1, 0),
+};
+
+#define WM8994_CLASS_W_SWITCH(xname, reg, shift, max, invert) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = snd_soc_info_volsw, \
+       .get = snd_soc_dapm_get_volsw, .put = wm8994_put_class_w, \
+       .private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
+
+static int wm8994_put_class_w(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = w->codec;
+       int ret;
+
+       ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
+
+       wm8994_update_class_w(codec);
+
+       return ret;
+}
+
+static const struct snd_kcontrol_new dac1l_mix[] = {
+WM8994_CLASS_W_SWITCH("Right Sidetone Switch", WM8994_DAC1_LEFT_MIXER_ROUTING,
+                     5, 1, 0),
+WM8994_CLASS_W_SWITCH("Left Sidetone Switch", WM8994_DAC1_LEFT_MIXER_ROUTING,
+                     4, 1, 0),
+WM8994_CLASS_W_SWITCH("AIF2 Switch", WM8994_DAC1_LEFT_MIXER_ROUTING,
+                     2, 1, 0),
+WM8994_CLASS_W_SWITCH("AIF1.2 Switch", WM8994_DAC1_LEFT_MIXER_ROUTING,
+                     1, 1, 0),
+WM8994_CLASS_W_SWITCH("AIF1.1 Switch", WM8994_DAC1_LEFT_MIXER_ROUTING,
+                     0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dac1r_mix[] = {
+WM8994_CLASS_W_SWITCH("Right Sidetone Switch", WM8994_DAC1_RIGHT_MIXER_ROUTING,
+                     5, 1, 0),
+WM8994_CLASS_W_SWITCH("Left Sidetone Switch", WM8994_DAC1_RIGHT_MIXER_ROUTING,
+                     4, 1, 0),
+WM8994_CLASS_W_SWITCH("AIF2 Switch", WM8994_DAC1_RIGHT_MIXER_ROUTING,
+                     2, 1, 0),
+WM8994_CLASS_W_SWITCH("AIF1.2 Switch", WM8994_DAC1_RIGHT_MIXER_ROUTING,
+                     1, 1, 0),
+WM8994_CLASS_W_SWITCH("AIF1.1 Switch", WM8994_DAC1_RIGHT_MIXER_ROUTING,
+                     0, 1, 0),
+};
+
+static const char *sidetone_text[] = {
+       "ADC/DMIC1", "DMIC2",
+};
+
+static const struct soc_enum sidetone1_enum =
+       SOC_ENUM_SINGLE(WM8994_SIDETONE, 0, 2, sidetone_text);
+
+static const struct snd_kcontrol_new sidetone1_mux =
+       SOC_DAPM_ENUM("Left Sidetone Mux", sidetone1_enum);
+
+static const struct soc_enum sidetone2_enum =
+       SOC_ENUM_SINGLE(WM8994_SIDETONE, 1, 2, sidetone_text);
+
+static const struct snd_kcontrol_new sidetone2_mux =
+       SOC_DAPM_ENUM("Right Sidetone Mux", sidetone2_enum);
+
+static const char *aif1dac_text[] = {
+       "AIF1DACDAT", "AIF3DACDAT",
+};
+
+static const struct soc_enum aif1dac_enum =
+       SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 0, 2, aif1dac_text);
+
+static const struct snd_kcontrol_new aif1dac_mux =
+       SOC_DAPM_ENUM("AIF1DAC Mux", aif1dac_enum);
+
+static const char *aif2dac_text[] = {
+       "AIF2DACDAT", "AIF3DACDAT",
+};
+
+static const struct soc_enum aif2dac_enum =
+       SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 1, 2, aif2dac_text);
+
+static const struct snd_kcontrol_new aif2dac_mux =
+       SOC_DAPM_ENUM("AIF2DAC Mux", aif2dac_enum);
+
+static const char *aif2adc_text[] = {
+       "AIF2ADCDAT", "AIF3DACDAT",
+};
+
+static const struct soc_enum aif2adc_enum =
+       SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 2, 2, aif2adc_text);
+
+static const struct snd_kcontrol_new aif2adc_mux =
+       SOC_DAPM_ENUM("AIF2ADC Mux", aif2adc_enum);
+
+static const char *aif3adc_text[] = {
+       "AIF1ADCDAT", "AIF2ADCDAT", "AIF2DACDAT",
+};
+
+static const struct soc_enum aif3adc_enum =
+       SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 3, 3, aif3adc_text);
+
+static const struct snd_kcontrol_new aif3adc_mux =
+       SOC_DAPM_ENUM("AIF3ADC Mux", aif3adc_enum);
+
+static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("DMIC1DAT"),
+SND_SOC_DAPM_INPUT("DMIC2DAT"),
+
+SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event,
+                   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_SUPPLY("DSP1CLK", WM8994_CLOCKING_1, 3, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("DSP2CLK", WM8994_CLOCKING_1, 2, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("DSPINTCLK", WM8994_CLOCKING_1, 1, 0, NULL, 0),
+
+SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8994_AIF1_CLOCKING_1, 0, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF1ADC1L", "AIF1 Capture",
+                    0, WM8994_POWER_MANAGEMENT_4, 9, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1ADC1R", "AIF1 Capture",
+                    0, WM8994_POWER_MANAGEMENT_4, 8, 0),
+SND_SOC_DAPM_AIF_IN("AIF1DAC1L", NULL, 0,
+                   WM8994_POWER_MANAGEMENT_5, 9, 0),
+SND_SOC_DAPM_AIF_IN("AIF1DAC1R", NULL, 0,
+                   WM8994_POWER_MANAGEMENT_5, 8, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF1ADC2L", "AIF1 Capture",
+                    0, WM8994_POWER_MANAGEMENT_4, 11, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1ADC2R", "AIF1 Capture",
+                    0, WM8994_POWER_MANAGEMENT_4, 10, 0),
+SND_SOC_DAPM_AIF_IN("AIF1DAC2L", NULL, 0,
+                   WM8994_POWER_MANAGEMENT_5, 11, 0),
+SND_SOC_DAPM_AIF_IN("AIF1DAC2R", NULL, 0,
+                   WM8994_POWER_MANAGEMENT_5, 10, 0),
+
+SND_SOC_DAPM_MIXER("AIF1ADC1L Mixer", SND_SOC_NOPM, 0, 0,
+                  aif1adc1l_mix, ARRAY_SIZE(aif1adc1l_mix)),
+SND_SOC_DAPM_MIXER("AIF1ADC1R Mixer", SND_SOC_NOPM, 0, 0,
+                  aif1adc1r_mix, ARRAY_SIZE(aif1adc1r_mix)),
+
+SND_SOC_DAPM_MIXER("AIF2DAC2L Mixer", SND_SOC_NOPM, 0, 0,
+                  aif2dac2l_mix, ARRAY_SIZE(aif2dac2l_mix)),
+SND_SOC_DAPM_MIXER("AIF2DAC2R Mixer", SND_SOC_NOPM, 0, 0,
+                  aif2dac2r_mix, ARRAY_SIZE(aif2dac2r_mix)),
+
+SND_SOC_DAPM_MUX("Left Sidetone", SND_SOC_NOPM, 0, 0, &sidetone1_mux),
+SND_SOC_DAPM_MUX("Right Sidetone", SND_SOC_NOPM, 0, 0, &sidetone2_mux),
+
+SND_SOC_DAPM_MIXER("DAC1L Mixer", SND_SOC_NOPM, 0, 0,
+                  dac1l_mix, ARRAY_SIZE(dac1l_mix)),
+SND_SOC_DAPM_MIXER("DAC1R Mixer", SND_SOC_NOPM, 0, 0,
+                  dac1r_mix, ARRAY_SIZE(dac1r_mix)),
+
+SND_SOC_DAPM_AIF_OUT("AIF2ADCL", NULL, 0,
+                    WM8994_POWER_MANAGEMENT_4, 13, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2ADCR", NULL, 0,
+                    WM8994_POWER_MANAGEMENT_4, 12, 0),
+SND_SOC_DAPM_AIF_IN("AIF2DACL", NULL, 0,
+                   WM8994_POWER_MANAGEMENT_5, 13, 0),
+SND_SOC_DAPM_AIF_IN("AIF2DACR", NULL, 0,
+                   WM8994_POWER_MANAGEMENT_5, 12, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF1DACDAT", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_IN("AIF2DACDAT", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2ADCDAT", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+SND_SOC_DAPM_MUX("AIF1DAC Mux", SND_SOC_NOPM, 0, 0, &aif1dac_mux),
+SND_SOC_DAPM_MUX("AIF2DAC Mux", SND_SOC_NOPM, 0, 0, &aif2dac_mux),
+SND_SOC_DAPM_MUX("AIF2ADC Mux", SND_SOC_NOPM, 0, 0, &aif2adc_mux),
+SND_SOC_DAPM_MUX("AIF3ADC Mux", SND_SOC_NOPM, 0, 0, &aif3adc_mux),
+
+SND_SOC_DAPM_AIF_IN("AIF3DACDAT", "AIF3 Playback", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_IN("AIF3ADCDAT", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+SND_SOC_DAPM_SUPPLY("TOCLK", WM8994_CLOCKING_1, 4, 0, NULL, 0),
+
+SND_SOC_DAPM_ADC("DMIC2L", NULL, WM8994_POWER_MANAGEMENT_4, 5, 0),
+SND_SOC_DAPM_ADC("DMIC2R", NULL, WM8994_POWER_MANAGEMENT_4, 4, 0),
+SND_SOC_DAPM_ADC("DMIC1L", NULL, WM8994_POWER_MANAGEMENT_4, 3, 0),
+SND_SOC_DAPM_ADC("DMIC1R", NULL, WM8994_POWER_MANAGEMENT_4, 2, 0),
+
+/* Power is done with the muxes since the ADC power also controls the
+ * downsampling chain, the chip will automatically manage the analogue
+ * specific portions.
+ */
+SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 1, 0),
+SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0),
+
+SND_SOC_DAPM_MUX("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux),
+SND_SOC_DAPM_MUX("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux),
+
+SND_SOC_DAPM_DAC("DAC2L", NULL, WM8994_POWER_MANAGEMENT_5, 3, 0),
+SND_SOC_DAPM_DAC("DAC2R", NULL, WM8994_POWER_MANAGEMENT_5, 2, 0),
+SND_SOC_DAPM_DAC("DAC1L", NULL, WM8994_POWER_MANAGEMENT_5, 1, 0),
+SND_SOC_DAPM_DAC("DAC1R", NULL, WM8994_POWER_MANAGEMENT_5, 0, 0),
+
+SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux),
+SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux),
+
+SND_SOC_DAPM_MIXER("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0,
+                  left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)),
+SND_SOC_DAPM_MIXER("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0,
+                  right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)),
+
+SND_SOC_DAPM_POST("Debug log", post_ev),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+
+       { "CLK_SYS", NULL, "AIF1CLK", check_clk_sys },
+       { "CLK_SYS", NULL, "AIF2CLK", check_clk_sys },
+
+       { "DSP1CLK", NULL, "CLK_SYS" },
+       { "DSP2CLK", NULL, "CLK_SYS" },
+       { "DSPINTCLK", NULL, "CLK_SYS" },
+
+       { "AIF1ADC1L", NULL, "AIF1CLK" },
+       { "AIF1ADC1L", NULL, "DSP1CLK" },
+       { "AIF1ADC1R", NULL, "AIF1CLK" },
+       { "AIF1ADC1R", NULL, "DSP1CLK" },
+       { "AIF1ADC1R", NULL, "DSPINTCLK" },
+
+       { "AIF1DAC1L", NULL, "AIF1CLK" },
+       { "AIF1DAC1L", NULL, "DSP1CLK" },
+       { "AIF1DAC1R", NULL, "AIF1CLK" },
+       { "AIF1DAC1R", NULL, "DSP1CLK" },
+       { "AIF1DAC1R", NULL, "DSPINTCLK" },
+
+       { "AIF1ADC2L", NULL, "AIF1CLK" },
+       { "AIF1ADC2L", NULL, "DSP1CLK" },
+       { "AIF1ADC2R", NULL, "AIF1CLK" },
+       { "AIF1ADC2R", NULL, "DSP1CLK" },
+       { "AIF1ADC2R", NULL, "DSPINTCLK" },
+
+       { "AIF1DAC2L", NULL, "AIF1CLK" },
+       { "AIF1DAC2L", NULL, "DSP1CLK" },
+       { "AIF1DAC2R", NULL, "AIF1CLK" },
+       { "AIF1DAC2R", NULL, "DSP1CLK" },
+       { "AIF1DAC2R", NULL, "DSPINTCLK" },
+
+       { "AIF2ADCL", NULL, "AIF2CLK" },
+       { "AIF2ADCL", NULL, "DSP2CLK" },
+       { "AIF2ADCR", NULL, "AIF2CLK" },
+       { "AIF2ADCR", NULL, "DSP2CLK" },
+       { "AIF2ADCR", NULL, "DSPINTCLK" },
+
+       { "AIF2DACL", NULL, "AIF2CLK" },
+       { "AIF2DACL", NULL, "DSP2CLK" },
+       { "AIF2DACR", NULL, "AIF2CLK" },
+       { "AIF2DACR", NULL, "DSP2CLK" },
+       { "AIF2DACR", NULL, "DSPINTCLK" },
+
+       { "DMIC1L", NULL, "DMIC1DAT" },
+       { "DMIC1L", NULL, "CLK_SYS" },
+       { "DMIC1R", NULL, "DMIC1DAT" },
+       { "DMIC1R", NULL, "CLK_SYS" },
+       { "DMIC2L", NULL, "DMIC2DAT" },
+       { "DMIC2L", NULL, "CLK_SYS" },
+       { "DMIC2R", NULL, "DMIC2DAT" },
+       { "DMIC2R", NULL, "CLK_SYS" },
+
+       { "ADCL", NULL, "AIF1CLK" },
+       { "ADCL", NULL, "DSP1CLK" },
+       { "ADCL", NULL, "DSPINTCLK" },
+
+       { "ADCR", NULL, "AIF1CLK" },
+       { "ADCR", NULL, "DSP1CLK" },
+       { "ADCR", NULL, "DSPINTCLK" },
+
+       { "ADCL Mux", "ADC", "ADCL" },
+       { "ADCL Mux", "DMIC", "DMIC1L" },
+       { "ADCR Mux", "ADC", "ADCR" },
+       { "ADCR Mux", "DMIC", "DMIC1R" },
+
+       { "DAC1L", NULL, "AIF1CLK" },
+       { "DAC1L", NULL, "DSP1CLK" },
+       { "DAC1L", NULL, "DSPINTCLK" },
+
+       { "DAC1R", NULL, "AIF1CLK" },
+       { "DAC1R", NULL, "DSP1CLK" },
+       { "DAC1R", NULL, "DSPINTCLK" },
+
+       { "DAC2L", NULL, "AIF2CLK" },
+       { "DAC2L", NULL, "DSP2CLK" },
+       { "DAC2L", NULL, "DSPINTCLK" },
+
+       { "DAC2R", NULL, "AIF2DACR" },
+       { "DAC2R", NULL, "AIF2CLK" },
+       { "DAC2R", NULL, "DSP2CLK" },
+       { "DAC2R", NULL, "DSPINTCLK" },
+
+       { "TOCLK", NULL, "CLK_SYS" },
+
+       /* AIF1 outputs */
+       { "AIF1ADC1L", NULL, "AIF1ADC1L Mixer" },
+       { "AIF1ADC1L Mixer", "ADC/DMIC Switch", "ADCL Mux" },
+       { "AIF1ADC1L Mixer", "AIF2 Switch", "AIF2DACL" },
+
+       { "AIF1ADC1R", NULL, "AIF1ADC1R Mixer" },
+       { "AIF1ADC1R Mixer", "ADC/DMIC Switch", "ADCR Mux" },
+       { "AIF1ADC1R Mixer", "AIF2 Switch", "AIF2DACR" },
+
+       /* Pin level routing for AIF3 */
+       { "AIF1DAC1L", NULL, "AIF1DAC Mux" },
+       { "AIF1DAC1R", NULL, "AIF1DAC Mux" },
+       { "AIF1DAC2L", NULL, "AIF1DAC Mux" },
+       { "AIF1DAC2R", NULL, "AIF1DAC Mux" },
+
+       { "AIF2DACL", NULL, "AIF2DAC Mux" },
+       { "AIF2DACR", NULL, "AIF2DAC Mux" },
+
+       { "AIF1DAC Mux", "AIF1DACDAT", "AIF1DACDAT" },
+       { "AIF1DAC Mux", "AIF3DACDAT", "AIF3DACDAT" },
+       { "AIF2DAC Mux", "AIF2DACDAT", "AIF2DACDAT" },
+       { "AIF2DAC Mux", "AIF3DACDAT", "AIF3DACDAT" },
+       { "AIF2ADC Mux", "AIF2ADCDAT", "AIF2ADCL" },
+       { "AIF2ADC Mux", "AIF2ADCDAT", "AIF2ADCR" },
+       { "AIF2ADC Mux", "AIF3DACDAT", "AIF3ADCDAT" },
+
+       /* DAC1 inputs */
+       { "DAC1L", NULL, "DAC1L Mixer" },
+       { "DAC1L Mixer", "AIF2 Switch", "AIF2DACL" },
+       { "DAC1L Mixer", "AIF1.2 Switch", "AIF1DAC2L" },
+       { "DAC1L Mixer", "AIF1.1 Switch", "AIF1DAC1L" },
+       { "DAC1L Mixer", "Left Sidetone Switch", "Left Sidetone" },
+       { "DAC1L Mixer", "Right Sidetone Switch", "Right Sidetone" },
+
+       { "DAC1R", NULL, "DAC1R Mixer" },
+       { "DAC1R Mixer", "AIF2 Switch", "AIF2DACR" },
+       { "DAC1R Mixer", "AIF1.2 Switch", "AIF1DAC2R" },
+       { "DAC1R Mixer", "AIF1.1 Switch", "AIF1DAC1R" },
+       { "DAC1R Mixer", "Left Sidetone Switch", "Left Sidetone" },
+       { "DAC1R Mixer", "Right Sidetone Switch", "Right Sidetone" },
+
+       /* DAC2/AIF2 outputs  */
+       { "AIF2ADCL", NULL, "AIF2DAC2L Mixer" },
+       { "DAC2L", NULL, "AIF2DAC2L Mixer" },
+       { "AIF2DAC2L Mixer", "AIF2 Switch", "AIF2DACL" },
+       { "AIF2DAC2L Mixer", "AIF1.2 Switch", "AIF1DAC2L" },
+       { "AIF2DAC2L Mixer", "AIF1.1 Switch", "AIF1DAC1L" },
+       { "AIF2DAC2L Mixer", "Left Sidetone Switch", "Left Sidetone" },
+       { "AIF2DAC2L Mixer", "Right Sidetone Switch", "Right Sidetone" },
+
+       { "AIF2ADCR", NULL, "AIF2DAC2R Mixer" },
+       { "DAC2R", NULL, "AIF2DAC2R Mixer" },
+       { "AIF2DAC2R Mixer", "AIF2 Switch", "AIF2DACR" },
+       { "AIF2DAC2R Mixer", "AIF1.2 Switch", "AIF1DAC2R" },
+       { "AIF2DAC2R Mixer", "AIF1.1 Switch", "AIF1DAC1R" },
+       { "AIF2DAC2R Mixer", "Left Sidetone Switch", "Left Sidetone" },
+       { "AIF2DAC2R Mixer", "Right Sidetone Switch", "Right Sidetone" },
+
+       { "AIF2ADCDAT", NULL, "AIF2ADC Mux" },
+
+       /* AIF3 output */
+       { "AIF3ADCDAT", "AIF1ADCDAT", "AIF1ADC1L" },
+       { "AIF3ADCDAT", "AIF1ADCDAT", "AIF1ADC1R" },
+       { "AIF3ADCDAT", "AIF1ADCDAT", "AIF1ADC2L" },
+       { "AIF3ADCDAT", "AIF1ADCDAT", "AIF1ADC2R" },
+       { "AIF3ADCDAT", "AIF2ADCDAT", "AIF2ADCL" },
+       { "AIF3ADCDAT", "AIF2ADCDAT", "AIF2ADCR" },
+       { "AIF3ADCDAT", "AIF2DACDAT", "AIF2DACL" },
+       { "AIF3ADCDAT", "AIF2DACDAT", "AIF2DACR" },
+
+       /* Sidetone */
+       { "Left Sidetone", "ADC/DMIC1", "ADCL Mux" },
+       { "Left Sidetone", "DMIC2", "DMIC2L" },
+       { "Right Sidetone", "ADC/DMIC1", "ADCR Mux" },
+       { "Right Sidetone", "DMIC2", "DMIC2R" },
+
+       /* Output stages */
+       { "Left Output Mixer", "DAC Switch", "DAC1L" },
+       { "Right Output Mixer", "DAC Switch", "DAC1R" },
+
+       { "SPKL", "DAC1 Switch", "DAC1L" },
+       { "SPKL", "DAC2 Switch", "DAC2L" },
+
+       { "SPKR", "DAC1 Switch", "DAC1R" },
+       { "SPKR", "DAC2 Switch", "DAC2R" },
+
+       { "Left Headphone Mux", "DAC", "DAC1L" },
+       { "Right Headphone Mux", "DAC", "DAC1R" },
+};
+
+/* The size in bits of the FLL divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_FLL_SIZE ((1 << 16) * 10)
+
+struct fll_div {
+       u16 outdiv;
+       u16 n;
+       u16 k;
+       u16 clk_ref_div;
+       u16 fll_fratio;
+};
+
+static int wm8994_get_fll_config(struct fll_div *fll,
+                                int freq_in, int freq_out)
+{
+       u64 Kpart;
+       unsigned int K, Ndiv, Nmod;
+
+       pr_debug("FLL input=%dHz, output=%dHz\n", freq_in, freq_out);
+
+       /* Scale the input frequency down to <= 13.5MHz */
+       fll->clk_ref_div = 0;
+       while (freq_in > 13500000) {
+               fll->clk_ref_div++;
+               freq_in /= 2;
+
+               if (fll->clk_ref_div > 3)
+                       return -EINVAL;
+       }
+       pr_debug("CLK_REF_DIV=%d, Fref=%dHz\n", fll->clk_ref_div, freq_in);
+
+       /* Scale the output to give 90MHz<=Fvco<=100MHz */
+       fll->outdiv = 3;
+       while (freq_out * (fll->outdiv + 1) < 90000000) {
+               fll->outdiv++;
+               if (fll->outdiv > 63)
+                       return -EINVAL;
+       }
+       freq_out *= fll->outdiv + 1;
+       pr_debug("OUTDIV=%d, Fvco=%dHz\n", fll->outdiv, freq_out);
+
+       if (freq_in > 1000000) {
+               fll->fll_fratio = 0;
+       } else {
+               fll->fll_fratio = 3;
+               freq_in *= 8;
+       }
+       pr_debug("FLL_FRATIO=%d, Fref=%dHz\n", fll->fll_fratio, freq_in);
+
+       /* Now, calculate N.K */
+       Ndiv = freq_out / freq_in;
+
+       fll->n = Ndiv;
+       Nmod = freq_out % freq_in;
+       pr_debug("Nmod=%d\n", Nmod);
+
+       /* Calculate fractional part - scale up so we can round. */
+       Kpart = FIXED_FLL_SIZE * (long long)Nmod;
+
+       do_div(Kpart, freq_in);
+
+       K = Kpart & 0xFFFFFFFF;
+
+       if ((K % 10) >= 5)
+               K += 5;
+
+       /* Move down to proper range now rounding is done */
+       fll->k = K / 10;
+
+       pr_debug("N=%x K=%x\n", fll->n, fll->k);
+
+       return 0;
+}
+
+static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src,
+                         unsigned int freq_in, unsigned int freq_out)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct wm8994_priv *wm8994 = codec->private_data;
+       int reg_offset, ret;
+       struct fll_div fll;
+       u16 reg, aif1, aif2;
+
+       aif1 = snd_soc_read(codec, WM8994_AIF1_CLOCKING_1)
+               & WM8994_AIF1CLK_ENA;
+
+       aif2 = snd_soc_read(codec, WM8994_AIF2_CLOCKING_1)
+               & WM8994_AIF2CLK_ENA;
+
+       switch (id) {
+       case WM8994_FLL1:
+               reg_offset = 0;
+               id = 0;
+               break;
+       case WM8994_FLL2:
+               reg_offset = 0x20;
+               id = 1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Are we changing anything? */
+       if (wm8994->fll[id].src == src &&
+           wm8994->fll[id].in == freq_in && wm8994->fll[id].out == freq_out)
+               return 0;
+
+       /* If we're stopping the FLL redo the old config - no
+        * registers will actually be written but we avoid GCC flow
+        * analysis bugs spewing warnings.
+        */
+       if (freq_out)
+               ret = wm8994_get_fll_config(&fll, freq_in, freq_out);
+       else
+               ret = wm8994_get_fll_config(&fll, wm8994->fll[id].in,
+                                           wm8994->fll[id].out);
+       if (ret < 0)
+               return ret;
+
+       /* Gate the AIF clocks while we reclock */
+       snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1,
+                           WM8994_AIF1CLK_ENA, 0);
+       snd_soc_update_bits(codec, WM8994_AIF2_CLOCKING_1,
+                           WM8994_AIF2CLK_ENA, 0);
+
+       /* We always need to disable the FLL while reconfiguring */
+       snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_1 + reg_offset,
+                           WM8994_FLL1_ENA, 0);
+
+       reg = (fll.outdiv << WM8994_FLL1_OUTDIV_SHIFT) |
+               (fll.fll_fratio << WM8994_FLL1_FRATIO_SHIFT);
+       snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_2 + reg_offset,
+                           WM8994_FLL1_OUTDIV_MASK |
+                           WM8994_FLL1_FRATIO_MASK, reg);
+
+       snd_soc_write(codec, WM8994_FLL1_CONTROL_3 + reg_offset, fll.k);
+
+       snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_4 + reg_offset,
+                           WM8994_FLL1_N_MASK,
+                                   fll.n << WM8994_FLL1_N_SHIFT);
+
+       snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset,
+                           WM8994_FLL1_REFCLK_DIV_MASK,
+                           fll.clk_ref_div << WM8994_FLL1_REFCLK_DIV_SHIFT);
+
+       /* Enable (with fractional mode if required) */
+       if (freq_out) {
+               if (fll.k)
+                       reg = WM8994_FLL1_ENA | WM8994_FLL1_FRAC;
+               else
+                       reg = WM8994_FLL1_ENA;
+               snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_1 + reg_offset,
+                                   WM8994_FLL1_ENA | WM8994_FLL1_FRAC,
+                                   reg);
+       }
+
+       wm8994->fll[id].in = freq_in;
+       wm8994->fll[id].out = freq_out;
+
+       /* Enable any gated AIF clocks */
+       snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1,
+                           WM8994_AIF1CLK_ENA, aif1);
+       snd_soc_update_bits(codec, WM8994_AIF2_CLOCKING_1,
+                           WM8994_AIF2CLK_ENA, aif2);
+
+       configure_clock(codec);
+
+       return 0;
+}
+
+static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
+               int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct wm8994_priv *wm8994 = codec->private_data;
+
+       switch (dai->id) {
+       case 1:
+       case 2:
+               break;
+
+       default:
+               /* AIF3 shares clocking with AIF1/2 */
+               return -EINVAL;
+       }
+
+       switch (clk_id) {
+       case WM8994_SYSCLK_MCLK1:
+               wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_MCLK1;
+               wm8994->mclk[0] = freq;
+               dev_dbg(dai->dev, "AIF%d using MCLK1 at %uHz\n",
+                       dai->id, freq);
+               break;
+
+       case WM8994_SYSCLK_MCLK2:
+               /* TODO: Set GPIO AF */
+               wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_MCLK2;
+               wm8994->mclk[1] = freq;
+               dev_dbg(dai->dev, "AIF%d using MCLK2 at %uHz\n",
+                       dai->id, freq);
+               break;
+
+       case WM8994_SYSCLK_FLL1:
+               wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_FLL1;
+               dev_dbg(dai->dev, "AIF%d using FLL1\n", dai->id);
+               break;
+
+       case WM8994_SYSCLK_FLL2:
+               wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_FLL2;
+               dev_dbg(dai->dev, "AIF%d using FLL2\n", dai->id);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       configure_clock(codec);
+
+       return 0;
+}
+
+static int wm8994_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:
+               /* VMID=2x40k */
+               snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
+                                   WM8994_VMID_SEL_MASK, 0x2);
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+                       /* Tweak DC servo configuration for improved
+                        * performance. */
+                       snd_soc_write(codec, 0x102, 0x3);
+                       snd_soc_write(codec, 0x56, 0x3);
+                       snd_soc_write(codec, 0x102, 0);
+
+                       /* Discharge LINEOUT1 & 2 */
+                       snd_soc_update_bits(codec, WM8994_ANTIPOP_1,
+                                           WM8994_LINEOUT1_DISCH |
+                                           WM8994_LINEOUT2_DISCH,
+                                           WM8994_LINEOUT1_DISCH |
+                                           WM8994_LINEOUT2_DISCH);
+
+                       /* Startup bias, VMID ramp & buffer */
+                       snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
+                                           WM8994_STARTUP_BIAS_ENA |
+                                           WM8994_VMID_BUF_ENA |
+                                           WM8994_VMID_RAMP_MASK,
+                                           WM8994_STARTUP_BIAS_ENA |
+                                           WM8994_VMID_BUF_ENA |
+                                           (0x11 << WM8994_VMID_RAMP_SHIFT));
+
+                       /* Main bias enable, VMID=2x40k */
+                       snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
+                                           WM8994_BIAS_ENA |
+                                           WM8994_VMID_SEL_MASK,
+                                           WM8994_BIAS_ENA | 0x2);
+
+                       msleep(20);
+               }
+
+               /* VMID=2x500k */
+               snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
+                                   WM8994_VMID_SEL_MASK, 0x4);
+
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               /* Switch over to startup biases */
+               snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
+                                   WM8994_BIAS_SRC | WM8994_STARTUP_BIAS_ENA |
+                                   WM8994_VMID_BUF_ENA |
+                                   WM8994_VMID_RAMP_MASK,
+                                   WM8994_BIAS_SRC | WM8994_STARTUP_BIAS_ENA |
+                                   WM8994_VMID_BUF_ENA |
+                                   (1 << WM8994_VMID_RAMP_SHIFT));
+
+               /* Disable main biases */
+               snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
+                                   WM8994_BIAS_ENA | WM8994_VMID_SEL_MASK, 0);
+
+               /* Discharge line */
+               snd_soc_update_bits(codec, WM8994_ANTIPOP_1,
+                                   WM8994_LINEOUT1_DISCH |
+                                   WM8994_LINEOUT2_DISCH,
+                                   WM8994_LINEOUT1_DISCH |
+                                   WM8994_LINEOUT2_DISCH);
+
+               msleep(5);
+
+               /* Switch off startup biases */
+               snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
+                                   WM8994_BIAS_SRC | WM8994_STARTUP_BIAS_ENA |
+                                   WM8994_VMID_BUF_ENA |
+                                   WM8994_VMID_RAMP_MASK, 0);
+
+               break;
+       }
+       codec->bias_level = level;
+       return 0;
+}
+
+static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       int ms_reg;
+       int aif1_reg;
+       int ms = 0;
+       int aif1 = 0;
+
+       switch (dai->id) {
+       case 1:
+               ms_reg = WM8994_AIF1_MASTER_SLAVE;
+               aif1_reg = WM8994_AIF1_CONTROL_1;
+               break;
+       case 2:
+               ms_reg = WM8994_AIF2_MASTER_SLAVE;
+               aif1_reg = WM8994_AIF2_CONTROL_1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               ms = WM8994_AIF1_MSTR;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_B:
+               aif1 |= WM8994_AIF1_LRCLK_INV;
+       case SND_SOC_DAIFMT_DSP_A:
+               aif1 |= 0x18;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               aif1 |= 0x10;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               aif1 |= 0x8;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_A:
+       case SND_SOC_DAIFMT_DSP_B:
+               /* frame inversion not valid for DSP modes */
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       aif1 |= WM8994_AIF1_BCLK_INV;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+
+       case SND_SOC_DAIFMT_I2S:
+       case SND_SOC_DAIFMT_RIGHT_J:
+       case SND_SOC_DAIFMT_LEFT_J:
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       break;
+               case SND_SOC_DAIFMT_IB_IF:
+                       aif1 |= WM8994_AIF1_BCLK_INV | WM8994_AIF1_LRCLK_INV;
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       aif1 |= WM8994_AIF1_BCLK_INV;
+                       break;
+               case SND_SOC_DAIFMT_NB_IF:
+                       aif1 |= WM8994_AIF1_LRCLK_INV;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, aif1_reg,
+                           WM8994_AIF1_BCLK_INV | WM8994_AIF1_LRCLK_INV |
+                           WM8994_AIF1_FMT_MASK,
+                           aif1);
+       snd_soc_update_bits(codec, ms_reg, WM8994_AIF1_MSTR,
+                           ms);
+
+       return 0;
+}
+
+static struct {
+       int val, rate;
+} srs[] = {
+       { 0,   8000 },
+       { 1,  11025 },
+       { 2,  12000 },
+       { 3,  16000 },
+       { 4,  22050 },
+       { 5,  24000 },
+       { 6,  32000 },
+       { 7,  44100 },
+       { 8,  48000 },
+       { 9,  88200 },
+       { 10, 96000 },
+};
+
+static int fs_ratios[] = {
+       64, 128, 192, 256, 348, 512, 768, 1024, 1408, 1536
+};
+
+static int bclk_divs[] = {
+       10, 15, 20, 30, 40, 50, 60, 80, 110, 120, 160, 220, 240, 320, 440, 480,
+       640, 880, 960, 1280, 1760, 1920
+};
+
+static int wm8994_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 wm8994_priv *wm8994 = codec->private_data;
+       int aif1_reg;
+       int bclk_reg;
+       int lrclk_reg;
+       int rate_reg;
+       int aif1 = 0;
+       int bclk = 0;
+       int lrclk = 0;
+       int rate_val = 0;
+       int id = dai->id - 1;
+
+       int i, cur_val, best_val, bclk_rate, best;
+
+       switch (dai->id) {
+       case 1:
+               aif1_reg = WM8994_AIF1_CONTROL_1;
+               bclk_reg = WM8994_AIF1_BCLK;
+               rate_reg = WM8994_AIF1_RATE;
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+                   wm8994->lrclk_shared[0])
+                       lrclk_reg = WM8994_AIF1DAC_LRCLK;
+               else
+                       lrclk_reg = WM8994_AIF1ADC_LRCLK;
+               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])
+                       lrclk_reg = WM8994_AIF2DAC_LRCLK;
+               else
+                       lrclk_reg = WM8994_AIF2ADC_LRCLK;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       bclk_rate = params_rate(params) * 2;
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               bclk_rate *= 16;
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               bclk_rate *= 20;
+               aif1 |= 0x20;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               bclk_rate *= 24;
+               aif1 |= 0x40;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               bclk_rate *= 32;
+               aif1 |= 0x60;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Try to find an appropriate sample rate; look for an exact match. */
+       for (i = 0; i < ARRAY_SIZE(srs); i++)
+               if (srs[i].rate == params_rate(params))
+                       break;
+       if (i == ARRAY_SIZE(srs))
+               return -EINVAL;
+       rate_val |= srs[i].val << WM8994_AIF1_SR_SHIFT;
+
+       dev_dbg(dai->dev, "Sample rate is %dHz\n", srs[i].rate);
+       dev_dbg(dai->dev, "AIF%dCLK is %dHz, target BCLK %dHz\n",
+               dai->id, wm8994->aifclk[id], bclk_rate);
+
+       if (wm8994->aifclk[id] == 0) {
+               dev_err(dai->dev, "AIF%dCLK not configured\n", dai->id);
+               return -EINVAL;
+       }
+
+       /* AIFCLK/fs ratio; look for a close match in either direction */
+       best = 0;
+       best_val = abs((fs_ratios[0] * params_rate(params))
+                      - wm8994->aifclk[id]);
+       for (i = 1; i < ARRAY_SIZE(fs_ratios); i++) {
+               cur_val = abs((fs_ratios[i] * params_rate(params))
+                             - wm8994->aifclk[id]);
+               if (cur_val >= best_val)
+                       continue;
+               best = i;
+               best_val = cur_val;
+       }
+       dev_dbg(dai->dev, "Selected AIF%dCLK/fs = %d\n",
+               dai->id, fs_ratios[best]);
+       rate_val |= best;
+
+       /* We may not get quite the right frequency if using
+        * approximate clocks so look for the closest match that is
+        * higher than the target (we need to ensure that there enough
+        * BCLKs to clock out the samples).
+        */
+       best = 0;
+       for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
+               cur_val = (wm8994->aifclk[id] * 10 / bclk_divs[i]) - bclk_rate;
+               if (cur_val < 0) /* BCLK table is sorted */
+                       break;
+               best = i;
+       }
+       bclk_rate = wm8994->aifclk[id] * 10 / bclk_divs[best];
+       dev_dbg(dai->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n",
+               bclk_divs[best], bclk_rate);
+       bclk |= best << WM8994_AIF1_BCLK_DIV_SHIFT;
+
+       lrclk = bclk_rate / params_rate(params);
+       dev_dbg(dai->dev, "Using LRCLK rate %d for actual LRCLK %dHz\n",
+               lrclk, bclk_rate / lrclk);
+
+       snd_soc_update_bits(codec, aif1_reg, WM8994_AIF1_WL_MASK, aif1);
+       snd_soc_update_bits(codec, bclk_reg, WM8994_AIF1_BCLK_DIV_MASK, bclk);
+       snd_soc_update_bits(codec, lrclk_reg, WM8994_AIF1DAC_RATE_MASK,
+                           lrclk);
+       snd_soc_update_bits(codec, rate_reg, WM8994_AIF1_SR_MASK |
+                           WM8994_AIF1CLK_RATE_MASK, rate_val);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               switch (dai->id) {
+               case 1:
+                       wm8994->dac_rates[0] = params_rate(params);
+                       wm8994_set_retune_mobile(codec, 0);
+                       wm8994_set_retune_mobile(codec, 1);
+                       break;
+               case 2:
+                       wm8994->dac_rates[1] = params_rate(params);
+                       wm8994_set_retune_mobile(codec, 2);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static int wm8994_aif_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       int mute_reg;
+       int reg;
+
+       switch (codec_dai->id) {
+       case 1:
+               mute_reg = WM8994_AIF1_DAC1_FILTERS_1;
+               break;
+       case 2:
+               mute_reg = WM8994_AIF2_DAC_FILTERS_1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (mute)
+               reg = WM8994_AIF1DAC1_MUTE;
+       else
+               reg = 0;
+
+       snd_soc_update_bits(codec, mute_reg, WM8994_AIF1DAC1_MUTE, reg);
+
+       return 0;
+}
+
+#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)
+
+static struct snd_soc_dai_ops wm8994_aif1_dai_ops = {
+       .set_sysclk     = wm8994_set_dai_sysclk,
+       .set_fmt        = wm8994_set_dai_fmt,
+       .hw_params      = wm8994_hw_params,
+       .digital_mute   = wm8994_aif_mute,
+       .set_pll        = wm8994_set_fll,
+};
+
+static struct snd_soc_dai_ops wm8994_aif2_dai_ops = {
+       .set_sysclk     = wm8994_set_dai_sysclk,
+       .set_fmt        = wm8994_set_dai_fmt,
+       .hw_params      = wm8994_hw_params,
+       .digital_mute   = wm8994_aif_mute,
+       .set_pll        = wm8994_set_fll,
+};
+
+struct snd_soc_dai wm8994_dai[] = {
+       {
+               .name = "WM8994 AIF1",
+               .id = 1,
+               .playback = {
+                       .stream_name = "AIF1 Playback",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = WM8994_RATES,
+                       .formats = WM8994_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "AIF1 Capture",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = WM8994_RATES,
+                       .formats = WM8994_FORMATS,
+                },
+               .ops = &wm8994_aif1_dai_ops,
+       },
+       {
+               .name = "WM8994 AIF2",
+               .id = 2,
+               .playback = {
+                       .stream_name = "AIF2 Playback",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = WM8994_RATES,
+                       .formats = WM8994_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "AIF2 Capture",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = WM8994_RATES,
+                       .formats = WM8994_FORMATS,
+               },
+               .ops = &wm8994_aif2_dai_ops,
+       },
+       {
+               .name = "WM8994 AIF3",
+               .playback = {
+                       .stream_name = "AIF3 Playback",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = WM8994_RATES,
+                       .formats = WM8994_FORMATS,
+               },
+               .playback = {
+                       .stream_name = "AIF3 Capture",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = WM8994_RATES,
+                       .formats = WM8994_FORMATS,
+               },
+       }
+};
+EXPORT_SYMBOL_GPL(wm8994_dai);
+
+#ifdef CONFIG_PM
+static int wm8994_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;
+       struct wm8994_priv *wm8994 = codec->private_data;
+       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);
+               if (ret < 0)
+                       dev_warn(codec->dev, "Failed to stop FLL%d: %d\n",
+                                i + 1, ret);
+       }
+
+       wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       return 0;
+}
+
+static int wm8994_resume(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->card->codec;
+       struct wm8994_priv *wm8994 = codec->private_data;
+       u16 *reg_cache = codec->reg_cache;
+       int i, ret;
+
+       /* Restore the registers */
+       for (i = 1; i < ARRAY_SIZE(wm8994->reg_cache); i++) {
+               switch (i) {
+               case WM8994_LDO_1:
+               case WM8994_LDO_2:
+               case WM8994_SOFTWARE_RESET:
+                       /* Handled by other MFD drivers */
+                       continue;
+               default:
+                       break;
+               }
+
+               if (!access_masks[i].writable)
+                       continue;
+
+               wm8994_reg_write(codec->control_data, i, reg_cache[i]);
+       }
+
+       wm8994_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) {
+               ret = wm8994_set_fll(&codec->dai[0], i + 1,
+                                    wm8994->fll_suspend[i].src,
+                                    wm8994->fll_suspend[i].in,
+                                    wm8994->fll_suspend[i].out);
+               if (ret < 0)
+                       dev_warn(codec->dev, "Failed to restore FLL%d: %d\n",
+                                i + 1, ret);
+       }
+
+       return 0;
+}
+#else
+#define wm8994_suspend NULL
+#define wm8994_resume NULL
+#endif
+
+static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)
+{
+       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",
+                            wm8994->retune_mobile_enum,
+                            wm8994_get_retune_mobile_enum,
+                            wm8994_put_retune_mobile_enum),
+               SOC_ENUM_EXT("AIF1.2 EQ Mode",
+                            wm8994->retune_mobile_enum,
+                            wm8994_get_retune_mobile_enum,
+                            wm8994_put_retune_mobile_enum),
+               SOC_ENUM_EXT("AIF2 EQ Mode",
+                            wm8994->retune_mobile_enum,
+                            wm8994_get_retune_mobile_enum,
+                            wm8994_put_retune_mobile_enum),
+       };
+       int ret, i, j;
+       const char **t;
+
+       /* We need an array of texts for the enum API but the number
+        * of texts is likely to be less than the number of
+        * configurations due to the sample rate dependency of the
+        * configurations. */
+       wm8994->num_retune_mobile_texts = 0;
+       wm8994->retune_mobile_texts = NULL;
+       for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) {
+               for (j = 0; j < wm8994->num_retune_mobile_texts; j++) {
+                       if (strcmp(pdata->retune_mobile_cfgs[i].name,
+                                  wm8994->retune_mobile_texts[j]) == 0)
+                               break;
+               }
+
+               if (j != wm8994->num_retune_mobile_texts)
+                       continue;
+
+               /* Expand the array... */
+               t = krealloc(wm8994->retune_mobile_texts,
+                            sizeof(char *) * 
+                            (wm8994->num_retune_mobile_texts + 1),
+                            GFP_KERNEL);
+               if (t == NULL)
+                       continue;
+
+               /* ...store the new entry... */
+               t[wm8994->num_retune_mobile_texts] = 
+                       pdata->retune_mobile_cfgs[i].name;
+
+               /* ...and remember the new version. */
+               wm8994->num_retune_mobile_texts++;
+               wm8994->retune_mobile_texts = t;
+       }
+
+       dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n",
+               wm8994->num_retune_mobile_texts);
+
+       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,
+                                  ARRAY_SIZE(controls));
+       if (ret != 0)
+               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 wm8994_pdata *pdata = wm8994->pdata;
+       int ret, i;
+
+       if (!pdata)
+               return;
+
+       wm_hubs_handle_analogue_pdata(codec, pdata->lineout1_diff,
+                                     pdata->lineout2_diff,
+                                     pdata->lineout1fb,
+                                     pdata->lineout2fb,
+                                     pdata->jd_scthr,
+                                     pdata->jd_thr,
+                                     pdata->micbias1_lvl,
+                                     pdata->micbias2_lvl);
+
+       dev_dbg(codec->dev, "%d DRC configurations\n", pdata->num_drc_cfgs);
+
+       if (pdata->num_drc_cfgs) {
+               struct snd_kcontrol_new controls[] = {
+                       SOC_ENUM_EXT("AIF1DRC1 Mode", wm8994->drc_enum,
+                                    wm8994_get_drc_enum, wm8994_put_drc_enum),
+                       SOC_ENUM_EXT("AIF1DRC2 Mode", wm8994->drc_enum,
+                                    wm8994_get_drc_enum, wm8994_put_drc_enum),
+                       SOC_ENUM_EXT("AIF2DRC Mode", wm8994->drc_enum,
+                                    wm8994_get_drc_enum, wm8994_put_drc_enum),
+               };
+
+               /* We need an array of texts for the enum API */
+               wm8994->drc_texts = kmalloc(sizeof(char *)
+                                           * pdata->num_drc_cfgs, GFP_KERNEL);
+               if (!wm8994->drc_texts) {
+                       dev_err(wm8994->codec.dev,
+                               "Failed to allocate %d DRC config texts\n",
+                               pdata->num_drc_cfgs);
+                       return;
+               }
+
+               for (i = 0; i < pdata->num_drc_cfgs; i++)
+                       wm8994->drc_texts[i] = pdata->drc_cfgs[i].name;
+
+               wm8994->drc_enum.max = pdata->num_drc_cfgs;
+               wm8994->drc_enum.texts = wm8994->drc_texts;
+
+               ret = snd_soc_add_controls(&wm8994->codec, controls,
+                                          ARRAY_SIZE(controls));
+               if (ret != 0)
+                       dev_err(wm8994->codec.dev,
+                               "Failed to add DRC mode controls: %d\n", ret);
+
+               for (i = 0; i < WM8994_NUM_DRC; i++)
+                       wm8994_set_drc(codec, i);
+       }
+
+       dev_dbg(codec->dev, "%d ReTune Mobile configurations\n",
+               pdata->num_retune_mobile_cfgs);
+
+       if (pdata->num_retune_mobile_cfgs)
+               wm8994_handle_retune_mobile_pdata(wm8994);
+       else
+               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(codec->private_data);
+
+       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);
+
+static int wm8994_codec_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct wm8994_priv *wm8994;
+       struct snd_soc_codec *codec;
+       int i;
+       u16 rev;
+
+       if (wm8994_codec) {
+               dev_err(&pdev->dev, "Another WM8994 is registered\n");
+               return -EINVAL;
+       }
+
+       wm8994 = kzalloc(sizeof(struct wm8994_priv), GFP_KERNEL);
+       if (!wm8994) {
+               dev_err(&pdev->dev, "Failed to allocate private data\n");
+               return -ENOMEM;
+       }
+
+       codec = &wm8994->codec;
+
+       mutex_init(&codec->mutex);
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+
+       codec->private_data = 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;
+
+       /* Fill the cache with physical values we inherited; don't reset */
+       ret = wm8994_bulk_read(codec->control_data, 0,
+                              ARRAY_SIZE(wm8994->reg_cache) - 1,
+                              codec->reg_cache);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to fill register cache: %d\n",
+                       ret);
+               goto err;
+       }
+
+       /* Clear the cached values for unreadable/volatile registers to
+        * avoid potential confusion.
+        */
+       for (i = 0; i < ARRAY_SIZE(wm8994->reg_cache); i++)
+               if (wm8994_volatile(i) || !wm8994_readable(i))
+                       wm8994->reg_cache[i] = 0;
+
+       /* Set revision-specific configuration */
+       rev = snd_soc_read(codec, WM8994_CHIP_REVISION);
+       switch (rev) {
+       case 2:
+       case 3:
+               wm8994->hubs.dcs_codes = -5;
+               wm8994->hubs.hp_startup_mode = 1;
+               break;
+       default:
+               break;
+       }
+                          
+
+       /* Remember if AIFnLRCLK is configured as a GPIO.  This should be
+        * configured on init - if a system wants to do this dynamically
+        * at runtime we can deal with that then.
+        */
+       ret = wm8994_reg_read(codec->control_data, WM8994_GPIO_1);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to read GPIO1 state: %d\n", ret);
+               goto err;
+       }
+       if ((ret & WM8994_GPN_FN_MASK) != WM8994_GP_FN_PIN_SPECIFIC) {
+               wm8994->lrclk_shared[0] = 1;
+               wm8994_dai[0].symmetric_rates = 1;
+       } else {
+               wm8994->lrclk_shared[0] = 0;
+       }
+
+       ret = wm8994_reg_read(codec->control_data, WM8994_GPIO_6);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to read GPIO6 state: %d\n", ret);
+               goto err;
+       }
+       if ((ret & WM8994_GPN_FN_MASK) != WM8994_GP_FN_PIN_SPECIFIC) {
+               wm8994->lrclk_shared[1] = 1;
+               wm8994_dai[1].symmetric_rates = 1;
+       } else {
+               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);
+       snd_soc_update_bits(codec, WM8994_AIF1_DAC2_RIGHT_VOLUME,
+                           WM8994_AIF1DAC2_VU, WM8994_AIF1DAC2_VU);
+       snd_soc_update_bits(codec, WM8994_AIF2_DAC_RIGHT_VOLUME,
+                           WM8994_AIF2DAC_VU, WM8994_AIF2DAC_VU);
+       snd_soc_update_bits(codec, WM8994_AIF1_ADC1_RIGHT_VOLUME,
+                           WM8994_AIF1ADC1_VU, WM8994_AIF1ADC1_VU);
+       snd_soc_update_bits(codec, WM8994_AIF1_ADC2_RIGHT_VOLUME,
+                           WM8994_AIF1ADC2_VU, WM8994_AIF1ADC2_VU);
+       snd_soc_update_bits(codec, WM8994_AIF2_ADC_RIGHT_VOLUME,
+                           WM8994_AIF2ADC_VU, WM8994_AIF1ADC2_VU);
+       snd_soc_update_bits(codec, WM8994_DAC1_RIGHT_VOLUME,
+                           WM8994_DAC1_VU, WM8994_DAC1_VU);
+       snd_soc_update_bits(codec, WM8994_DAC2_RIGHT_VOLUME,
+                           WM8994_DAC2_VU, WM8994_DAC2_VU);
+
+       /* Set the low bit of the 3D stereo depth so TLV matches */
+       snd_soc_update_bits(codec, WM8994_AIF1_DAC1_FILTERS_2,
+                           1 << WM8994_AIF1DAC1_3D_GAIN_SHIFT,
+                           1 << WM8994_AIF1DAC1_3D_GAIN_SHIFT);
+       snd_soc_update_bits(codec, WM8994_AIF1_DAC2_FILTERS_2,
+                           1 << WM8994_AIF1DAC2_3D_GAIN_SHIFT,
+                           1 << WM8994_AIF1DAC2_3D_GAIN_SHIFT);
+       snd_soc_update_bits(codec, WM8994_AIF2_DAC_FILTERS_2,
+                           1 << WM8994_AIF2DAC_3D_GAIN_SHIFT,
+                           1 << WM8994_AIF2DAC_3D_GAIN_SHIFT);
+
+       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;
+       }
+
+       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;
+       }
+
+       platform_set_drvdata(pdev, wm8994);
+
+       return 0;
+
+err_codec:
+       snd_soc_unregister_codec(codec);
+err:
+       kfree(wm8994);
+       return ret;
+}
+
+static int __devexit wm8994_codec_remove(struct platform_device *pdev)
+{
+       struct wm8994_priv *wm8994 = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = &wm8994->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);
+       kfree(wm8994);
+       wm8994_codec = NULL;
+
+       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),
+};
+
+static __init int wm8994_init(void)
+{
+       return platform_driver_register(&wm8994_codec_driver);
+}
+module_init(wm8994_init);
+
+static __exit void wm8994_exit(void)
+{
+       platform_driver_unregister(&wm8994_codec_driver);
+}
+module_exit(wm8994_exit);
+
+
+MODULE_DESCRIPTION("ASoC WM8994 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm8994-codec");
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h
new file mode 100644 (file)
index 0000000..0a5e142
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * wm8994.h  --  WM8994 Soc Audio driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8994_H
+#define _WM8994_H
+
+#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
+#define WM8994_SYSCLK_FLL1  3
+#define WM8994_SYSCLK_FLL2  4
+
+#define WM8994_FLL1 1
+#define WM8994_FLL2 2
+
+#endif
index c58aab375edbd4c59ee6e10187e7ccdcdd2322af..ceb86b4ddb25286076d00fb5fc7aeffce9e234bc 100644 (file)
 #include <sound/ac97_codec.h>
 #include <sound/initval.h>
 #include <sound/pcm_params.h>
+#include <sound/tlv.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 
 #include "wm9713.h"
 
-#define WM9713_VERSION "0.15"
-
 struct wm9713_priv {
        u32 pll_in; /* PLL input frequency */
 };
@@ -115,15 +114,27 @@ SOC_ENUM_SINGLE(AC97_3D_CONTROL, 12, 3, wm9713_mic_select), /* mic selection 18
 SOC_ENUM_SINGLE(MICB_MUX, 0, 2, wm9713_micb_select), /* mic selection 19 */
 };
 
+static const DECLARE_TLV_DB_SCALE(out_tlv, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(main_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(misc_tlv, -1500, 300, 0);
+static unsigned int mic_tlv[] = {
+       TLV_DB_RANGE_HEAD(2),
+       0, 2, TLV_DB_SCALE_ITEM(1200, 600, 0),
+       3, 3, TLV_DB_SCALE_ITEM(3000, 0, 0),
+};
+
 static const struct snd_kcontrol_new wm9713_snd_ac97_controls[] = {
-SOC_DOUBLE("Speaker Playback Volume", AC97_MASTER, 8, 0, 31, 1),
+SOC_DOUBLE_TLV("Speaker Playback Volume", AC97_MASTER, 8, 0, 31, 1, out_tlv),
 SOC_DOUBLE("Speaker Playback Switch", AC97_MASTER, 15, 7, 1, 1),
-SOC_DOUBLE("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1),
+SOC_DOUBLE_TLV("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1,
+              out_tlv),
 SOC_DOUBLE("Headphone Playback Switch", AC97_HEADPHONE, 15, 7, 1, 1),
-SOC_DOUBLE("Line In Volume", AC97_PC_BEEP, 8, 0, 31, 1),
-SOC_DOUBLE("PCM Playback Volume", AC97_PHONE, 8, 0, 31, 1),
-SOC_SINGLE("Mic 1 Volume", AC97_MIC, 8, 31, 1),
-SOC_SINGLE("Mic 2 Volume", AC97_MIC, 0, 31, 1),
+SOC_DOUBLE_TLV("Line In Volume", AC97_PC_BEEP, 8, 0, 31, 1, main_tlv),
+SOC_DOUBLE_TLV("PCM Playback Volume", AC97_PHONE, 8, 0, 31, 1, main_tlv),
+SOC_SINGLE_TLV("Mic 1 Volume", AC97_MIC, 8, 31, 1, main_tlv),
+SOC_SINGLE_TLV("Mic 2 Volume", AC97_MIC, 0, 31, 1, main_tlv),
+SOC_SINGLE_TLV("Mic 1 Preamp Volume", AC97_3D_CONTROL, 10, 3, 0, mic_tlv),
+SOC_SINGLE_TLV("Mic 2 Preamp Volume", AC97_3D_CONTROL, 12, 3, 0, mic_tlv),
 
 SOC_SINGLE("Mic Boost (+20dB) Switch", AC97_LINE, 5, 1, 0),
 SOC_SINGLE("Mic Headphone Mixer Volume", AC97_LINE, 0, 7, 1),
@@ -133,7 +144,7 @@ SOC_ENUM("Capture Volume Steps", wm9713_enum[5]),
 SOC_DOUBLE("Capture Volume", AC97_CD, 8, 0, 31, 0),
 SOC_SINGLE("Capture ZC Switch", AC97_CD, 7, 1, 0),
 
-SOC_SINGLE("Capture to Headphone Volume", AC97_VIDEO, 11, 7, 1),
+SOC_SINGLE_TLV("Capture to Headphone Volume", AC97_VIDEO, 11, 7, 1, misc_tlv),
 SOC_SINGLE("Capture to Mono Boost (+20dB) Switch", AC97_VIDEO, 8, 1, 0),
 SOC_SINGLE("Capture ADC Boost (+20dB) Switch", AC97_VIDEO, 6, 1, 0),
 
@@ -154,28 +165,43 @@ SOC_DOUBLE("Headphone Playback ZC Switch", AC97_HEADPHONE, 14, 6, 1, 0),
 
 SOC_SINGLE("Out4 Playback Switch", AC97_MASTER_MONO, 15, 1, 1),
 SOC_SINGLE("Out4 Playback ZC Switch", AC97_MASTER_MONO, 14, 1, 0),
-SOC_SINGLE("Out4 Playback Volume", AC97_MASTER_MONO, 8, 63, 1),
+SOC_SINGLE_TLV("Out4 Playback Volume", AC97_MASTER_MONO, 8, 31, 1, out_tlv),
 
 SOC_SINGLE("Out3 Playback Switch", AC97_MASTER_MONO, 7, 1, 1),
 SOC_SINGLE("Out3 Playback ZC Switch", AC97_MASTER_MONO, 6, 1, 0),
-SOC_SINGLE("Out3 Playback Volume", AC97_MASTER_MONO, 0, 63, 1),
+SOC_SINGLE_TLV("Out3 Playback Volume", AC97_MASTER_MONO, 0, 31, 1, out_tlv),
 
-SOC_SINGLE("Mono Capture Volume", AC97_MASTER_TONE, 8, 31, 1),
+SOC_SINGLE_TLV("Mono Capture Volume", AC97_MASTER_TONE, 8, 31, 1, main_tlv),
 SOC_SINGLE("Mono Playback Switch", AC97_MASTER_TONE, 7, 1, 1),
 SOC_SINGLE("Mono Playback ZC Switch", AC97_MASTER_TONE, 6, 1, 0),
-SOC_SINGLE("Mono Playback Volume", AC97_MASTER_TONE, 0, 31, 1),
+SOC_SINGLE_TLV("Mono Playback Volume", AC97_MASTER_TONE, 0, 31, 1, out_tlv),
 
-SOC_SINGLE("Beep Playback Headphone Volume", AC97_AUX, 12, 7, 1),
-SOC_SINGLE("Beep Playback Speaker Volume", AC97_AUX, 8, 7, 1),
-SOC_SINGLE("Beep Playback Mono Volume", AC97_AUX, 4, 7, 1),
+SOC_SINGLE_TLV("Headphone Mixer Beep Playback Volume", AC97_AUX, 12, 7, 1,
+              misc_tlv),
+SOC_SINGLE_TLV("Speaker Mixer Beep Playback Volume", AC97_AUX, 8, 7, 1,
+              misc_tlv),
+SOC_SINGLE_TLV("Mono Mixer Beep Playback Volume", AC97_AUX, 4, 7, 1, misc_tlv),
 
-SOC_SINGLE("Voice Playback Headphone Volume", AC97_PCM, 12, 7, 1),
+SOC_SINGLE_TLV("Voice Playback Headphone Volume", AC97_PCM, 12, 7, 1,
+              misc_tlv),
 SOC_SINGLE("Voice Playback Master Volume", AC97_PCM, 8, 7, 1),
 SOC_SINGLE("Voice Playback Mono Volume", AC97_PCM, 4, 7, 1),
 
+SOC_SINGLE_TLV("Headphone Mixer Aux Playback Volume", AC97_REC_SEL, 12, 7, 1,
+              misc_tlv),
+
+SOC_SINGLE_TLV("Speaker Mixer Voice Playback Volume", AC97_PCM, 8, 7, 1,
+              misc_tlv),
+SOC_SINGLE_TLV("Speaker Mixer Aux Playback Volume", AC97_REC_SEL, 8, 7, 1,
+              misc_tlv),
+
+SOC_SINGLE_TLV("Mono Mixer Voice Playback Volume", AC97_PCM, 4, 7, 1,
+              misc_tlv),
+SOC_SINGLE_TLV("Mono Mixer Aux Playback Volume", AC97_REC_SEL, 4, 7, 1,
+              misc_tlv),
+
 SOC_SINGLE("Aux Playback Headphone Volume", AC97_REC_SEL, 12, 7, 1),
 SOC_SINGLE("Aux Playback Master Volume", AC97_REC_SEL, 8, 7, 1),
-SOC_SINGLE("Aux Playback Mono Volume", AC97_REC_SEL, 4, 7, 1),
 
 SOC_ENUM("Bass Control", wm9713_enum[16]),
 SOC_SINGLE("Bass Cut-off Switch", AC97_GENERAL_PURPOSE, 12, 1, 1),
@@ -1186,8 +1212,6 @@ static int wm9713_soc_probe(struct platform_device *pdev)
        struct snd_soc_codec *codec;
        int ret = 0, reg;
 
-       printk(KERN_INFO "WM9713/WM9714 SoC Audio Codec %s\n", WM9713_VERSION);
-
        socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec),
                                      GFP_KERNEL);
        if (socdev->card->codec == NULL)
index d73c30536a2cd158e09ce0cb760efcfc4db34376..0ad9f5d536c67bf89afe1172ef863cff2fdfd6d0 100644 (file)
@@ -68,24 +68,77 @@ static void wait_for_dc_servo(struct snd_soc_codec *codec)
        int count = 0;
 
        dev_dbg(codec->dev, "Waiting for DC servo...\n");
+
        do {
                count++;
                msleep(1);
                reg = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_0);
-               dev_dbg(codec->dev, "DC servo status: %x\n", reg);
-       } while ((reg & WM8993_DCS_CAL_COMPLETE_MASK)
-                != WM8993_DCS_CAL_COMPLETE_MASK && count < 1000);
+               dev_dbg(codec->dev, "DC servo: %x\n", reg);
+       } while (reg & WM8993_DCS_DATAPATH_BUSY);
 
-       if ((reg & WM8993_DCS_CAL_COMPLETE_MASK)
-           != WM8993_DCS_CAL_COMPLETE_MASK)
+       if (reg & WM8993_DCS_DATAPATH_BUSY)
                dev_err(codec->dev, "Timed out waiting for DC Servo\n");
 }
 
+/*
+ * Startup calibration of the DC servo
+ */
+static void calibrate_dc_servo(struct snd_soc_codec *codec)
+{
+       struct wm_hubs_data *hubs = codec->private_data;
+       u16 reg, dcs_cfg;
+
+       /* Set for 32 series updates */
+       snd_soc_update_bits(codec, WM8993_DC_SERVO_1,
+                           WM8993_DCS_SERIES_NO_01_MASK,
+                           32 << WM8993_DCS_SERIES_NO_01_SHIFT);
+
+       /* Enable the DC servo.  Write all bits to avoid triggering startup
+        * or write calibration.
+        */
+       snd_soc_update_bits(codec, WM8993_DC_SERVO_0,
+                           0xFFFF,
+                           WM8993_DCS_ENA_CHAN_0 |
+                           WM8993_DCS_ENA_CHAN_1 |
+                           WM8993_DCS_TRIG_SERIES_1 |
+                           WM8993_DCS_TRIG_SERIES_0);
+
+       wait_for_dc_servo(codec);
+
+       /* Apply correction to DC servo result */
+       if (hubs->dcs_codes) {
+               dev_dbg(codec->dev, "Applying %d code DC servo correction\n",
+                       hubs->dcs_codes);
+
+               /* HPOUT1L */
+               reg = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_1) &
+                       WM8993_DCS_INTEG_CHAN_0_MASK;;
+               reg += hubs->dcs_codes;
+               dcs_cfg = reg << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
+
+               /* HPOUT1R */
+               reg = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2) &
+                       WM8993_DCS_INTEG_CHAN_1_MASK;
+               reg += hubs->dcs_codes;
+               dcs_cfg |= reg;
+
+               /* Do it */
+               snd_soc_write(codec, WM8993_DC_SERVO_3, dcs_cfg);
+               snd_soc_update_bits(codec, WM8993_DC_SERVO_0,
+                                   WM8993_DCS_TRIG_DAC_WR_0 |
+                                   WM8993_DCS_TRIG_DAC_WR_1,
+                                   WM8993_DCS_TRIG_DAC_WR_0 |
+                                   WM8993_DCS_TRIG_DAC_WR_1);
+
+               wait_for_dc_servo(codec);
+       }
+}
+
 /*
  * Update the DC servo calibration on gain changes
  */
 static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol,
-                             struct snd_ctl_elem_value *ucontrol)
+                              struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
        int ret;
@@ -251,6 +304,47 @@ SOC_SINGLE_TLV("LINEOUT2 Volume", WM8993_LINE_OUTPUTS_VOLUME, 0, 1, 1,
               line_tlv),
 };
 
+static int hp_supply_event(struct snd_soc_dapm_widget *w,
+                          struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct wm_hubs_data *hubs = codec->private_data;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               switch (hubs->hp_startup_mode) {
+               case 0:
+                       break;
+               case 1:
+                       /* Enable the headphone amp */
+                       snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
+                                           WM8993_HPOUT1L_ENA |
+                                           WM8993_HPOUT1R_ENA,
+                                           WM8993_HPOUT1L_ENA |
+                                           WM8993_HPOUT1R_ENA);
+
+                       /* Enable the second stage */
+                       snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0,
+                                           WM8993_HPOUT1L_DLY |
+                                           WM8993_HPOUT1R_DLY,
+                                           WM8993_HPOUT1L_DLY |
+                                           WM8993_HPOUT1R_DLY);
+                       break;
+               default:
+                       dev_err(codec->dev, "Unknown HP startup mode %d\n",
+                               hubs->hp_startup_mode);
+                       break;
+               }
+
+       case SND_SOC_DAPM_PRE_PMD:
+               snd_soc_update_bits(codec, WM8993_CHARGE_PUMP_1,
+                                   WM8993_CP_ENA, 0);
+               break;
+       }
+
+       return 0;
+}
+
 static int hp_event(struct snd_soc_dapm_widget *w,
                    struct snd_kcontrol *kcontrol, int event)
 {
@@ -271,14 +365,11 @@ static int hp_event(struct snd_soc_dapm_widget *w,
                reg |= WM8993_HPOUT1L_DLY | WM8993_HPOUT1R_DLY;
                snd_soc_write(codec, WM8993_ANALOGUE_HP_0, reg);
 
-               /* Start the DC servo */
-               snd_soc_update_bits(codec, WM8993_DC_SERVO_0,
-                                   0xFFFF,
-                                   WM8993_DCS_ENA_CHAN_0 |
-                                   WM8993_DCS_ENA_CHAN_1 |
-                                   WM8993_DCS_TRIG_STARTUP_1 |
-                                   WM8993_DCS_TRIG_STARTUP_0);
-               wait_for_dc_servo(codec);
+               /* Smallest supported update interval */
+               snd_soc_update_bits(codec, WM8993_DC_SERVO_1,
+                                   WM8993_DCS_TIMER_PERIOD_01_MASK, 1);
+
+               calibrate_dc_servo(codec);
 
                reg |= WM8993_HPOUT1R_OUTP | WM8993_HPOUT1R_RMV_SHORT |
                        WM8993_HPOUT1L_OUTP | WM8993_HPOUT1L_RMV_SHORT;
@@ -286,23 +377,19 @@ static int hp_event(struct snd_soc_dapm_widget *w,
                break;
 
        case SND_SOC_DAPM_PRE_PMD:
-               reg &= ~(WM8993_HPOUT1L_RMV_SHORT |
-                        WM8993_HPOUT1L_DLY |
-                        WM8993_HPOUT1L_OUTP |
-                        WM8993_HPOUT1R_RMV_SHORT |
-                        WM8993_HPOUT1R_DLY |
-                        WM8993_HPOUT1R_OUTP);
+               snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0,
+                                   WM8993_HPOUT1L_DLY |
+                                   WM8993_HPOUT1R_DLY |
+                                   WM8993_HPOUT1L_RMV_SHORT |
+                                   WM8993_HPOUT1R_RMV_SHORT, 0);
 
-               snd_soc_update_bits(codec, WM8993_DC_SERVO_0,
-                                   0xffff, 0);
+               snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0,
+                                   WM8993_HPOUT1L_OUTP |
+                                   WM8993_HPOUT1R_OUTP, 0);
 
-               snd_soc_write(codec, WM8993_ANALOGUE_HP_0, reg);
                snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
                                    WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA,
                                    0);
-
-               snd_soc_update_bits(codec, WM8993_CHARGE_PUMP_1,
-                                   WM8993_CP_ENA, 0);
                break;
        }
 
@@ -473,6 +560,8 @@ SND_SOC_DAPM_MIXER("Right Output Mixer", WM8993_POWER_MANAGEMENT_3, 4, 0,
 SND_SOC_DAPM_PGA("Left Output PGA", WM8993_POWER_MANAGEMENT_3, 7, 0, NULL, 0),
 SND_SOC_DAPM_PGA("Right Output PGA", WM8993_POWER_MANAGEMENT_3, 6, 0, NULL, 0),
 
+SND_SOC_DAPM_SUPPLY("Headphone Supply", SND_SOC_NOPM, 0, 0, hp_supply_event, 
+                   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
 SND_SOC_DAPM_PGA_E("Headphone PGA", SND_SOC_NOPM, 0, 0,
                   NULL, 0,
                   hp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
@@ -626,6 +715,7 @@ static const struct snd_soc_dapm_route analogue_routes[] = {
        { "Headphone PGA", NULL, "Left Headphone Mux" },
        { "Headphone PGA", NULL, "Right Headphone Mux" },
        { "Headphone PGA", NULL, "CLK_SYS" },
+       { "Headphone PGA", NULL, "Headphone Supply" },
 
        { "HPOUT1L", NULL, "Headphone PGA" },
        { "HPOUT1R", NULL, "Headphone PGA" },
@@ -753,6 +843,12 @@ int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *codec,
                                    WM8993_LINEOUT2_MODE,
                                    WM8993_LINEOUT2_MODE);
 
+       /* If the line outputs are differential then we aren't presenting
+        * VMID as an output and can disable it.
+        */
+       if (lineout1_diff && lineout2_diff)
+               codec->idle_bias_off = 1;
+
        if (lineout1fb)
                snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL,
                                    WM8993_LINEOUT1_FB, WM8993_LINEOUT1_FB);
index 36d3fba1de8b560ee414d5092461c844e0fa3f86..420104fe9c90467a1c9027c3e9bc234cab28ecc8 100644 (file)
@@ -18,6 +18,12 @@ struct snd_soc_codec;
 
 extern const unsigned int wm_hubs_spkmix_tlv[];
 
+/* This *must* be the first element of the codec->private_data struct */
+struct wm_hubs_data {
+       int dcs_codes;
+       int hp_startup_mode;
+};
+
 extern int wm_hubs_add_analogue_controls(struct snd_soc_codec *);
 extern int wm_hubs_add_analogue_routes(struct snd_soc_codec *, int, int);
 extern int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *,
index 0a302e1080d9ec06553d77dfb12125b4fcece380..ab6518d86f1886c14b18fe4c436cba2a9d6c2f07 100644 (file)
@@ -767,14 +767,26 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
        int ret = 0;
 
        switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               if (!dev->clk_active) {
+                       clk_enable(dev->clk);
+                       dev->clk_active = 1;
+               }
                davinci_mcasp_start(dev, substream->stream);
                break;
 
-       case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
+               davinci_mcasp_stop(dev, substream->stream);
+               if (dev->clk_active) {
+                       clk_disable(dev->clk);
+                       dev->clk_active = 0;
+               }
+
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
                davinci_mcasp_stop(dev, substream->stream);
                break;
@@ -866,6 +878,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        }
 
        clk_enable(dev->clk);
+       dev->clk_active = 1;
 
        dev->base = (void __iomem *)IO_ADDRESS(mem->start);
        dev->op_mode = pdata->op_mode;
index 582c9249ef09b4cb0a4a53222ab7dd4b323a58cb..e755b5121ec728be29aed547b662c02994b2dc50 100644 (file)
@@ -44,6 +44,7 @@ struct davinci_audio_dev {
        int sample_rate;
        struct clk *clk;
        unsigned int codec_fmt;
+       u8 clk_active;
 
        /* McASP specific data */
        int     tdm_slots;
index ad4d7f47a86b01f985ffebeea5818f27d1f67a3c..80c7fdf2f521542d83babc9855d3a362de545a19 100644 (file)
@@ -49,7 +49,7 @@ static void print_buf_info(int slot, char *name)
 static struct snd_pcm_hardware pcm_hardware_playback = {
        .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
                 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
-                SNDRV_PCM_INFO_PAUSE),
+                SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
        .formats = (SNDRV_PCM_FMTBIT_S16_LE),
        .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
                  SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
index a700562e86925053946b2289b3f9069548f10e80..c7d0fd9b7de884522ee02f1ef838dccd8ed53269 100644 (file)
@@ -1,21 +1,13 @@
-config SND_MX1_MX2_SOC
-       tristate "SoC Audio for Freecale i.MX1x i.MX2x CPUs"
-       depends on ARCH_MX2 || ARCH_MX1
+config SND_IMX_SOC
+       tristate "SoC Audio for Freescale i.MX CPUs"
+       depends on ARCH_MXC && BROKEN
        select SND_PCM
+       select FIQ
+       select SND_SOC_AC97_BUS
        help
          Say Y or M if you want to add support for codecs attached to
-         the MX1 or MX2 SSI interface.
+         the i.MX SSI interface.
 
 config SND_MXC_SOC_SSI
        tristate
 
-config SND_SOC_MX27VIS_WM8974
-       tristate "SoC Audio support for MX27 - WM8974 Visstrim_sm10 board"
-       depends on SND_MX1_MX2_SOC && MACH_MX27 && MACH_IMX27_VISSTRIM_M10
-       select SND_MXC_SOC_SSI
-       select SND_SOC_WM8974
-       help
-         Say Y if you want to add support for SoC audio on Visstrim SM10
-         board with WM8974.
-
-
index c2ffd2c8df5a03efc56f0d4c98c31206dc1cfdd9..9f8bb92ddfcc0cf3406ecf09fe2f2ad46e2628e1 100644 (file)
@@ -1,10 +1,12 @@
 # i.MX Platform Support
-snd-soc-mx1_mx2-objs := mx1_mx2-pcm.o
-snd-soc-mxc-ssi-objs := mxc-ssi.o
+snd-soc-imx-objs := imx-ssi.o imx-pcm-fiq.o
 
-obj-$(CONFIG_SND_MX1_MX2_SOC) += snd-soc-mx1_mx2.o
-obj-$(CONFIG_SND_MXC_SOC_SSI) += snd-soc-mxc-ssi.o
+ifdef CONFIG_MACH_MX27
+snd-soc-imx-objs += imx-pcm-dma-mx2.o
+endif
+
+obj-$(CONFIG_SND_IMX_SOC) += snd-soc-imx.o
 
 # i.MX Machine Support
-snd-soc-mx27vis-wm8974-objs := mx27vis_wm8974.o
-obj-$(CONFIG_SND_SOC_MX27VIS_WM8974) += snd-soc-mx27vis-wm8974.o
+snd-soc-phycore-ac97-objs := phycore-ac97.o
+obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o
diff --git a/sound/soc/imx/imx-pcm-dma-mx2.c b/sound/soc/imx/imx-pcm-dma-mx2.c
new file mode 100644 (file)
index 0000000..19452e4
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ * imx-pcm-dma-mx2.c  --  ALSA Soc Audio Layer
+ *
+ * Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * This code is based on code copyrighted by Freescale,
+ * Liam Girdwood, Javier Martin and probably others.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the 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/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <mach/dma-mx1-mx2.h>
+
+#include "imx-ssi.h"
+
+struct imx_pcm_runtime_data {
+       int sg_count;
+       struct scatterlist *sg_list;
+       int period;
+       int periods;
+       unsigned long dma_addr;
+       int dma;
+       struct snd_pcm_substream *substream;
+       unsigned long offset;
+       unsigned long size;
+       unsigned long period_cnt;
+       void *buf;
+       int period_time;
+};
+
+/* Called by the DMA framework when a period has elapsed */
+static void imx_ssi_dma_progression(int channel, void *data,
+                                       struct scatterlist *sg)
+{
+       struct snd_pcm_substream *substream = data;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct imx_pcm_runtime_data *iprtd = runtime->private_data;
+
+       if (!sg)
+               return;
+
+       runtime = iprtd->substream->runtime;
+
+       iprtd->offset = sg->dma_address - runtime->dma_addr;
+
+       snd_pcm_period_elapsed(iprtd->substream);
+}
+
+static void imx_ssi_dma_callback(int channel, void *data)
+{
+       pr_err("%s shouldn't be called\n", __func__);
+}
+
+static void snd_imx_dma_err_callback(int channel, void *data, int err)
+{
+       pr_err("DMA error callback called\n");
+
+       pr_err("DMA timeout on channel %d -%s%s%s%s\n",
+                channel,
+                err & IMX_DMA_ERR_BURST ?    " burst" : "",
+                err & IMX_DMA_ERR_REQUEST ?  " request" : "",
+                err & IMX_DMA_ERR_TRANSFER ? " transfer" : "",
+                err & IMX_DMA_ERR_BUFFER ?   " buffer" : "");
+}
+
+static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct imx_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct imx_pcm_runtime_data *iprtd = runtime->private_data;
+       int ret;
+
+       iprtd->dma = imx_dma_request_by_prio(DRV_NAME, DMA_PRIO_HIGH);
+       if (iprtd->dma < 0) {
+               pr_err("Failed to claim the audio DMA\n");
+               return -ENODEV;
+       }
+
+       ret = imx_dma_setup_handlers(iprtd->dma,
+                               imx_ssi_dma_callback,
+                               snd_imx_dma_err_callback, substream);
+       if (ret)
+               goto out;
+
+       ret = imx_dma_setup_progression_handler(iprtd->dma,
+                       imx_ssi_dma_progression);
+       if (ret) {
+               pr_err("Failed to setup the DMA handler\n");
+               goto out;
+       }
+
+       ret = imx_dma_config_channel(iprtd->dma,
+                       IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
+                       IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
+                       dma_params->dma, 1);
+       if (ret < 0) {
+               pr_err("Cannot configure DMA channel: %d\n", ret);
+               goto out;
+       }
+
+       imx_dma_config_burstlen(iprtd->dma, dma_params->burstsize * 2);
+
+       return 0;
+out:
+       imx_dma_free(iprtd->dma);
+       return ret;
+}
+
+static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct imx_pcm_runtime_data *iprtd = runtime->private_data;
+       int i;
+       unsigned long dma_addr;
+
+       imx_ssi_dma_alloc(substream);
+
+       iprtd->size = params_buffer_bytes(params);
+       iprtd->periods = params_periods(params);
+       iprtd->period = params_period_bytes(params);
+       iprtd->offset = 0;
+       iprtd->period_time = HZ / (params_rate(params) /
+                       params_period_size(params));
+
+       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+       if (iprtd->sg_count != iprtd->periods) {
+               kfree(iprtd->sg_list);
+
+               iprtd->sg_list = kcalloc(iprtd->periods + 1,
+                               sizeof(struct scatterlist), GFP_KERNEL);
+               if (!iprtd->sg_list)
+                       return -ENOMEM;
+               iprtd->sg_count = iprtd->periods + 1;
+       }
+
+       sg_init_table(iprtd->sg_list, iprtd->sg_count);
+       dma_addr = runtime->dma_addr;
+
+       for (i = 0; i < iprtd->periods; i++) {
+               iprtd->sg_list[i].page_link = 0;
+               iprtd->sg_list[i].offset = 0;
+               iprtd->sg_list[i].dma_address = dma_addr;
+               iprtd->sg_list[i].length = iprtd->period;
+               dma_addr += iprtd->period;
+       }
+
+       /* close the loop */
+       iprtd->sg_list[iprtd->sg_count - 1].offset = 0;
+       iprtd->sg_list[iprtd->sg_count - 1].length = 0;
+       iprtd->sg_list[iprtd->sg_count - 1].page_link =
+                       ((unsigned long) iprtd->sg_list | 0x01) & ~0x02;
+       return 0;
+}
+
+static int snd_imx_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct imx_pcm_runtime_data *iprtd = runtime->private_data;
+
+       if (iprtd->dma >= 0) {
+               imx_dma_free(iprtd->dma);
+               iprtd->dma = -EINVAL;
+       }
+
+       kfree(iprtd->sg_list);
+       iprtd->sg_list = NULL;
+
+       return 0;
+}
+
+static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct imx_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data;
+       struct imx_pcm_runtime_data *iprtd = runtime->private_data;
+       int err;
+
+       iprtd->substream = substream;
+       iprtd->buf = (unsigned int *)substream->dma_buffer.area;
+       iprtd->period_cnt = 0;
+
+       pr_debug("%s: buf: %p period: %d periods: %d\n",
+                       __func__, iprtd->buf, iprtd->period, iprtd->periods);
+
+       err = imx_dma_setup_sg(iprtd->dma, iprtd->sg_list, iprtd->sg_count,
+                       IMX_DMA_LENGTH_LOOP, dma_params->dma_addr,
+                       substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+                       DMA_MODE_WRITE : DMA_MODE_READ);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct imx_pcm_runtime_data *iprtd = runtime->private_data;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               imx_dma_enable(iprtd->dma);
+
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               imx_dma_disable(iprtd->dma);
+
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static snd_pcm_uframes_t snd_imx_pcm_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct imx_pcm_runtime_data *iprtd = runtime->private_data;
+
+       return bytes_to_frames(substream->runtime, iprtd->offset);
+}
+
+static struct snd_pcm_hardware snd_imx_hardware = {
+       .info = SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_MMAP_VALID |
+               SNDRV_PCM_INFO_PAUSE |
+               SNDRV_PCM_INFO_RESUME,
+       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       .rate_min = 8000,
+       .channels_min = 2,
+       .channels_max = 2,
+       .buffer_bytes_max = IMX_SSI_DMABUF_SIZE,
+       .period_bytes_min = 128,
+       .period_bytes_max = 16 * 1024,
+       .periods_min = 2,
+       .periods_max = 255,
+       .fifo_size = 0,
+};
+
+static int snd_imx_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct imx_pcm_runtime_data *iprtd;
+       int ret;
+
+       iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL);
+       runtime->private_data = iprtd;
+
+       ret = snd_pcm_hw_constraint_integer(substream->runtime,
+                       SNDRV_PCM_HW_PARAM_PERIODS);
+       if (ret < 0)
+               return ret;
+
+       snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware);
+       return 0;
+}
+
+static struct snd_pcm_ops imx_pcm_ops = {
+       .open           = snd_imx_open,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = snd_imx_pcm_hw_params,
+       .hw_free        = snd_imx_pcm_hw_free,
+       .prepare        = snd_imx_pcm_prepare,
+       .trigger        = snd_imx_pcm_trigger,
+       .pointer        = snd_imx_pcm_pointer,
+       .mmap           = snd_imx_pcm_mmap,
+};
+
+static struct snd_soc_platform imx_soc_platform_dma = {
+       .name           = "imx-audio",
+       .pcm_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)
+{
+       ssi->dma_params_tx.burstsize = DMA_TXFIFO_BURST;
+       ssi->dma_params_rx.burstsize = DMA_RXFIFO_BURST;
+
+       return &imx_soc_platform_dma;
+}
+
diff --git a/sound/soc/imx/imx-pcm-fiq.c b/sound/soc/imx/imx-pcm-fiq.c
new file mode 100644 (file)
index 0000000..d9cb984
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * imx-pcm-fiq.c  --  ALSA Soc Audio Layer
+ *
+ * Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * This code is based on code copyrighted by Freescale,
+ * Liam Girdwood, Javier Martin and probably others.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the 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/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/fiq.h>
+
+#include <mach/ssi.h>
+
+#include "imx-ssi.h"
+
+struct imx_pcm_runtime_data {
+       int period;
+       int periods;
+       unsigned long offset;
+       unsigned long last_offset;
+       unsigned long size;
+       struct timer_list timer;
+       int poll_time;
+};
+
+static inline void imx_ssi_set_next_poll(struct imx_pcm_runtime_data *iprtd)
+{
+       iprtd->timer.expires = jiffies + iprtd->poll_time;
+}
+
+static void imx_ssi_timer_callback(unsigned long data)
+{
+       struct snd_pcm_substream *substream = (void *)data;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct imx_pcm_runtime_data *iprtd = runtime->private_data;
+       struct pt_regs regs;
+       unsigned long delta;
+
+       get_fiq_regs(&regs);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               iprtd->offset = regs.ARM_r8 & 0xffff;
+       else
+               iprtd->offset = regs.ARM_r9 & 0xffff;
+
+       /* How much data have we transferred since the last period report? */
+       if (iprtd->offset >= iprtd->last_offset)
+               delta = iprtd->offset - iprtd->last_offset;
+       else
+               delta = runtime->buffer_size + iprtd->offset
+                       - iprtd->last_offset;
+
+       /* If we've transferred at least a period then report it and
+        * reset our poll time */
+       if (delta >= runtime->period_size) {
+               snd_pcm_period_elapsed(substream);
+               iprtd->last_offset = iprtd->offset;
+
+               imx_ssi_set_next_poll(iprtd);
+       }
+
+       /* Restart the timer; if we didn't report we'll run on the next tick */
+       add_timer(&iprtd->timer);
+
+}
+
+static struct fiq_handler fh = {
+       .name           = DRV_NAME,
+};
+
+static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct imx_pcm_runtime_data *iprtd = runtime->private_data;
+
+       iprtd->size = params_buffer_bytes(params);
+       iprtd->periods = params_periods(params);
+       iprtd->period = params_period_bytes(params) ;
+       iprtd->offset = 0;
+       iprtd->last_offset = 0;
+       iprtd->poll_time = HZ / (params_rate(params) / params_period_size(params));
+
+       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+       return 0;
+}
+
+static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct imx_pcm_runtime_data *iprtd = runtime->private_data;
+       struct pt_regs regs;
+
+       get_fiq_regs(&regs);
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               regs.ARM_r8 = (iprtd->period * iprtd->periods - 1) << 16;
+       else
+               regs.ARM_r9 = (iprtd->period * iprtd->periods - 1) << 16;
+
+       set_fiq_regs(&regs);
+
+       return 0;
+}
+
+static int fiq_enable;
+static int imx_pcm_fiq;
+
+static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct imx_pcm_runtime_data *iprtd = runtime->private_data;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               imx_ssi_set_next_poll(iprtd);
+               add_timer(&iprtd->timer);
+               if (++fiq_enable == 1)
+                       enable_fiq(imx_pcm_fiq);
+
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               del_timer(&iprtd->timer);
+               if (--fiq_enable == 0)
+                       disable_fiq(imx_pcm_fiq);
+
+
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static snd_pcm_uframes_t snd_imx_pcm_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct imx_pcm_runtime_data *iprtd = runtime->private_data;
+
+       return bytes_to_frames(substream->runtime, iprtd->offset);
+}
+
+static struct snd_pcm_hardware snd_imx_hardware = {
+       .info = SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_MMAP_VALID |
+               SNDRV_PCM_INFO_PAUSE |
+               SNDRV_PCM_INFO_RESUME,
+       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       .rate_min = 8000,
+       .channels_min = 2,
+       .channels_max = 2,
+       .buffer_bytes_max = IMX_SSI_DMABUF_SIZE,
+       .period_bytes_min = 128,
+       .period_bytes_max = 16 * 1024,
+       .periods_min = 2,
+       .periods_max = 255,
+       .fifo_size = 0,
+};
+
+static int snd_imx_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct imx_pcm_runtime_data *iprtd;
+       int ret;
+
+       iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL);
+       runtime->private_data = iprtd;
+
+       init_timer(&iprtd->timer);
+       iprtd->timer.data = (unsigned long)substream;
+       iprtd->timer.function = imx_ssi_timer_callback;
+
+       ret = snd_pcm_hw_constraint_integer(substream->runtime,
+                       SNDRV_PCM_HW_PARAM_PERIODS);
+       if (ret < 0)
+               return ret;
+
+       snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware);
+       return 0;
+}
+
+static int snd_imx_close(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct imx_pcm_runtime_data *iprtd = runtime->private_data;
+
+       del_timer_sync(&iprtd->timer);
+       kfree(iprtd);
+
+       return 0;
+}
+
+static struct snd_pcm_ops imx_pcm_ops = {
+       .open           = snd_imx_open,
+       .close          = snd_imx_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = snd_imx_pcm_hw_params,
+       .prepare        = snd_imx_pcm_prepare,
+       .trigger        = snd_imx_pcm_trigger,
+       .pointer        = snd_imx_pcm_pointer,
+       .mmap           = snd_imx_pcm_mmap,
+};
+
+static int imx_pcm_fiq_new(struct snd_card *card, struct snd_soc_dai *dai,
+       struct snd_pcm *pcm)
+{
+       int ret;
+
+       ret = imx_pcm_new(card, dai, pcm);
+       if (ret)
+               return ret;
+
+       if (dai->playback.channels_min) {
+               struct snd_pcm_substream *substream =
+                       pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+               struct snd_dma_buffer *buf = &substream->dma_buffer;
+
+               imx_ssi_fiq_tx_buffer = (unsigned long)buf->area;
+       }
+
+       if (dai->capture.channels_min) {
+               struct snd_pcm_substream *substream =
+                       pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
+               struct snd_dma_buffer *buf = &substream->dma_buffer;
+
+               imx_ssi_fiq_rx_buffer = (unsigned long)buf->area;
+       }
+
+       set_fiq_handler(&imx_ssi_fiq_start,
+               &imx_ssi_fiq_end - &imx_ssi_fiq_start);
+
+       return 0;
+}
+
+static struct snd_soc_platform imx_soc_platform_fiq = {
+       .pcm_ops        = &imx_pcm_ops,
+       .pcm_new        = imx_pcm_fiq_new,
+       .pcm_free       = imx_pcm_free,
+};
+
+struct snd_soc_platform *imx_ssi_fiq_init(struct platform_device *pdev,
+               struct imx_ssi *ssi)
+{
+       int ret = 0;
+
+       ret = claim_fiq(&fh);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to claim fiq: %d", ret);
+               return ERR_PTR(ret);
+       }
+
+       mxc_set_irq_fiq(ssi->irq, 1);
+
+       imx_pcm_fiq = ssi->irq;
+
+       imx_ssi_fiq_base = (unsigned long)ssi->base;
+
+       ssi->dma_params_tx.burstsize = 4;
+       ssi->dma_params_rx.burstsize = 6;
+
+       return &imx_soc_platform_fiq;
+}
+
+void imx_ssi_fiq_exit(struct platform_device *pdev,
+               struct imx_ssi *ssi)
+{
+       mxc_set_irq_fiq(ssi->irq, 0);
+       release_fiq(&fh);
+}
+
diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c
new file mode 100644 (file)
index 0000000..56f46a7
--- /dev/null
@@ -0,0 +1,758 @@
+/*
+ * imx-ssi.c  --  ALSA Soc Audio Layer
+ *
+ * Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * This code is based on code copyrighted by Freescale,
+ * Liam Girdwood, Javier Martin and probably others.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *
+ * The i.MX SSI core has some nasty limitations in AC97 mode. While most
+ * sane processor vendors have a FIFO per AC97 slot, the i.MX has only
+ * one FIFO which combines all valid receive slots. We cannot even select
+ * which slots we want to receive. The WM9712 with which this driver
+ * was developped with always sends GPIO status data in slot 12 which
+ * we receive in our (PCM-) data stream. The only chance we have is to
+ * manually skip this data in the FIQ handler. With sampling rates different
+ * from 48000Hz not every frame has valid receive data, so the ratio
+ * between pcm data and GPIO status data changes. Our FIQ handler is not
+ * able to handle this, hence this driver only works with 48000Hz sampling
+ * rate.
+ * Reading and writing AC97 registers is another challange. The core
+ * provides us status bits when the read register is updated with *another*
+ * value. When we read the same register two times (and the register still
+ * contains the same value) these status bits are not set. We work
+ * around this by not polling these bits but only wait a fixed delay.
+ * 
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <mach/ssi.h>
+#include <mach/hardware.h>
+
+#include "imx-ssi.h"
+
+#define SSI_SACNT_DEFAULT (SSI_SACNT_AC97EN | SSI_SACNT_FV)
+
+/*
+ * SSI Network Mode or TDM slots configuration.
+ * Should only be called when port is inactive (i.e. SSIEN = 0).
+ */
+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;
+       u32 sccr;
+
+       sccr = readl(ssi->base + SSI_STCCR);
+       sccr &= ~SSI_STCCR_DC_MASK;
+       sccr |= SSI_STCCR_DC(slots - 1);
+       writel(sccr, ssi->base + SSI_STCCR);
+
+       sccr = readl(ssi->base + SSI_SRCCR);
+       sccr &= ~SSI_STCCR_DC_MASK;
+       sccr |= SSI_STCCR_DC(slots - 1);
+       writel(sccr, ssi->base + SSI_SRCCR);
+
+       writel(tx_mask, ssi->base + SSI_STMSK);
+       writel(rx_mask, ssi->base + SSI_SRMSK);
+
+       return 0;
+}
+
+/*
+ * SSI DAI format configuration.
+ * Should only be called when port is inactive (i.e. SSIEN = 0).
+ * Note: We don't use the I2S modes but instead manually configure the
+ * SSI for I2S because the I2S mode is only a register preset.
+ */
+static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+{
+       struct imx_ssi *ssi = cpu_dai->private_data;
+       u32 strcr = 0, scr;
+
+       scr = readl(ssi->base + SSI_SCR) & ~(SSI_SCR_SYN | SSI_SCR_NET);
+
+       /* DAI mode */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               /* data on rising edge of bclk, frame low 1clk before data */
+               strcr |= SSI_STCR_TFSI | SSI_STCR_TEFS | SSI_STCR_TXBIT0;
+               scr |= SSI_SCR_NET;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               /* data on rising edge of bclk, frame high with data */
+               strcr |= SSI_STCR_TXBIT0;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               /* data on rising edge of bclk, frame high with data */
+               strcr |= SSI_STCR_TFSL;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               /* data on rising edge of bclk, frame high 1clk before data */
+               strcr |= SSI_STCR_TFSL | SSI_STCR_TEFS;
+               break;
+       }
+
+       /* DAI clock inversion */
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_IB_IF:
+               strcr |= SSI_STCR_TFSI;
+               strcr &= ~SSI_STCR_TSCKP;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               strcr &= ~(SSI_STCR_TSCKP | SSI_STCR_TFSI);
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               strcr |= SSI_STCR_TFSI | SSI_STCR_TSCKP;
+               break;
+       case SND_SOC_DAIFMT_NB_NF:
+               strcr &= ~SSI_STCR_TFSI;
+               strcr |= SSI_STCR_TSCKP;
+               break;
+       }
+
+       /* DAI clock master masks */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               break;
+       default:
+               /* Master mode not implemented, needs handling of clocks. */
+               return -EINVAL;
+       }
+
+       strcr |= SSI_STCR_TFEN0;
+
+       writel(strcr, ssi->base + SSI_STCR);
+       writel(strcr, ssi->base + SSI_SRCR);
+       writel(scr, ssi->base + SSI_SCR);
+
+       return 0;
+}
+
+/*
+ * SSI system clock configuration.
+ * Should only be called when port is inactive (i.e. SSIEN = 0).
+ */
+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;
+       u32 scr;
+
+       scr = readl(ssi->base + SSI_SCR);
+
+       switch (clk_id) {
+       case IMX_SSP_SYS_CLK:
+               if (dir == SND_SOC_CLOCK_OUT)
+                       scr |= SSI_SCR_SYS_CLK_EN;
+               else
+                       scr &= ~SSI_SCR_SYS_CLK_EN;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       writel(scr, ssi->base + SSI_SCR);
+
+       return 0;
+}
+
+/*
+ * SSI Clock dividers
+ * Should only be called when port is inactive (i.e. SSIEN = 0).
+ */
+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;
+       u32 stccr, srccr;
+
+       stccr = readl(ssi->base + SSI_STCCR);
+       srccr = readl(ssi->base + SSI_SRCCR);
+
+       switch (div_id) {
+       case IMX_SSI_TX_DIV_2:
+               stccr &= ~SSI_STCCR_DIV2;
+               stccr |= div;
+               break;
+       case IMX_SSI_TX_DIV_PSR:
+               stccr &= ~SSI_STCCR_PSR;
+               stccr |= div;
+               break;
+       case IMX_SSI_TX_DIV_PM:
+               stccr &= ~0xff;
+               stccr |= SSI_STCCR_PM(div);
+               break;
+       case IMX_SSI_RX_DIV_2:
+               stccr &= ~SSI_STCCR_DIV2;
+               stccr |= div;
+               break;
+       case IMX_SSI_RX_DIV_PSR:
+               stccr &= ~SSI_STCCR_PSR;
+               stccr |= div;
+               break;
+       case IMX_SSI_RX_DIV_PM:
+               stccr &= ~0xff;
+               stccr |= SSI_STCCR_PM(div);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       writel(stccr, ssi->base + SSI_STCCR);
+       writel(srccr, ssi->base + SSI_SRCCR);
+
+       return 0;
+}
+
+/*
+ * Should only be called when port is inactive (i.e. SSIEN = 0),
+ * although can be called multiple times by upper layers.
+ */
+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;
+       u32 reg, sccr;
+
+       /* Tx/Rx config */
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               reg = SSI_STCCR;
+               cpu_dai->dma_data = &ssi->dma_params_tx;
+       } else {
+               reg = SSI_SRCCR;
+               cpu_dai->dma_data = &ssi->dma_params_rx;
+       }
+
+       sccr = readl(ssi->base + reg) & ~SSI_STCCR_WL_MASK;
+
+       /* DAI data (word) size */
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               sccr |= SSI_SRCCR_WL(16);
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               sccr |= SSI_SRCCR_WL(20);
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               sccr |= SSI_SRCCR_WL(24);
+               break;
+       }
+
+       writel(sccr, ssi->base + reg);
+
+       return 0;
+}
+
+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;
+       unsigned int sier_bits, sier;
+       unsigned int scr;
+
+       scr = readl(ssi->base + SSI_SCR);
+       sier = readl(ssi->base + SSI_SIER);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               if (ssi->flags & IMX_SSI_DMA)
+                       sier_bits = SSI_SIER_TDMAE;
+               else
+                       sier_bits = SSI_SIER_TIE | SSI_SIER_TFE0_EN;
+       } else {
+               if (ssi->flags & IMX_SSI_DMA)
+                       sier_bits = SSI_SIER_RDMAE;
+               else
+                       sier_bits = SSI_SIER_RIE | SSI_SIER_RFF0_EN;
+       }
+
+       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)
+                       scr |= SSI_SCR_TE;
+               else
+                       scr |= SSI_SCR_RE;
+               sier |= sier_bits;
+
+               if (++ssi->enabled == 1)
+                       scr |= SSI_SCR_SSIEN;
+
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       scr &= ~SSI_SCR_TE;
+               else
+                       scr &= ~SSI_SCR_RE;
+               sier &= ~sier_bits;
+
+               if (--ssi->enabled == 0)
+                       scr &= ~SSI_SCR_SSIEN;
+
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (!(ssi->flags & IMX_SSI_USE_AC97))
+               /* rx/tx are always enabled to access ac97 registers */
+               writel(scr, ssi->base + SSI_SCR);
+
+       writel(sier, ssi->base + SSI_SIER);
+
+       return 0;
+}
+
+static struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = {
+       .hw_params      = imx_ssi_hw_params,
+       .set_fmt        = imx_ssi_set_dai_fmt,
+       .set_clkdiv     = imx_ssi_set_dai_clkdiv,
+       .set_sysclk     = imx_ssi_set_dai_sysclk,
+       .set_tdm_slot   = imx_ssi_set_dai_tdm_slot,
+       .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)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int ret;
+
+       ret = dma_mmap_coherent(NULL, vma, runtime->dma_area,
+                       runtime->dma_addr, runtime->dma_bytes);
+
+       pr_debug("%s: ret: %d %p 0x%08x 0x%08x\n", __func__, ret,
+                       runtime->dma_area,
+                       runtime->dma_addr,
+                       runtime->dma_bytes);
+       return ret;
+}
+
+static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+       struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+       struct snd_dma_buffer *buf = &substream->dma_buffer;
+       size_t size = IMX_SSI_DMABUF_SIZE;
+
+       buf->dev.type = SNDRV_DMA_TYPE_DEV;
+       buf->dev.dev = pcm->card->dev;
+       buf->private_data = NULL;
+       buf->area = dma_alloc_writecombine(pcm->card->dev, size,
+                                          &buf->addr, GFP_KERNEL);
+       if (!buf->area)
+               return -ENOMEM;
+       buf->bytes = size;
+
+       return 0;
+}
+
+static u64 imx_pcm_dmamask = DMA_BIT_MASK(32);
+
+int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
+       struct snd_pcm *pcm)
+{
+
+       int ret = 0;
+
+       if (!card->dev->dma_mask)
+               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) {
+               ret = imx_pcm_preallocate_dma_buffer(pcm,
+                       SNDRV_PCM_STREAM_PLAYBACK);
+               if (ret)
+                       goto out;
+       }
+
+       if (dai->capture.channels_min) {
+               ret = imx_pcm_preallocate_dma_buffer(pcm,
+                       SNDRV_PCM_STREAM_CAPTURE);
+               if (ret)
+                       goto out;
+       }
+
+out:
+       return ret;
+}
+
+void imx_pcm_free(struct snd_pcm *pcm)
+{
+       struct snd_pcm_substream *substream;
+       struct snd_dma_buffer *buf;
+       int stream;
+
+       for (stream = 0; stream < 2; stream++) {
+               substream = pcm->streams[stream].substream;
+               if (!substream)
+                       continue;
+
+               buf = &substream->dma_buffer;
+               if (!buf->area)
+                       continue;
+
+               dma_free_writecombine(pcm->card->dev, buf->bytes,
+                                     buf->area, buf->addr);
+               buf->area = NULL;
+       }
+}
+
+struct snd_soc_platform imx_soc_platform = {
+       .name           = "imx-audio",
+};
+EXPORT_SYMBOL_GPL(imx_soc_platform);
+
+static struct snd_soc_dai imx_ac97_dai = {
+       .name = "AC97",
+       .ac97_control = 1,
+       .playback = {
+               .stream_name = "AC97 Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .capture = {
+               .stream_name = "AC97 Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .ops = &imx_ssi_pcm_dai_ops,
+};
+
+static void setup_channel_to_ac97(struct imx_ssi *imx_ssi)
+{
+       void __iomem *base = imx_ssi->base;
+
+       writel(0x0, base + SSI_SCR);
+       writel(0x0, base + SSI_STCR);
+       writel(0x0, base + SSI_SRCR);
+
+       writel(SSI_SCR_SYN | SSI_SCR_NET, base + SSI_SCR);
+
+       writel(SSI_SFCSR_RFWM0(8) |
+               SSI_SFCSR_TFWM0(8) |
+               SSI_SFCSR_RFWM1(8) |
+               SSI_SFCSR_TFWM1(8), base + SSI_SFCSR);
+
+       writel(SSI_STCCR_WL(16) | SSI_STCCR_DC(12), base + SSI_STCCR);
+       writel(SSI_STCCR_WL(16) | SSI_STCCR_DC(12), base + SSI_SRCCR);
+
+       writel(SSI_SCR_SYN | SSI_SCR_NET | SSI_SCR_SSIEN, base + SSI_SCR);
+       writel(SSI_SOR_WAIT(3), base + SSI_SOR);
+
+       writel(SSI_SCR_SYN | SSI_SCR_NET | SSI_SCR_SSIEN |
+                       SSI_SCR_TE | SSI_SCR_RE,
+                       base + SSI_SCR);
+
+       writel(SSI_SACNT_DEFAULT, base + SSI_SACNT);
+       writel(0xff, base + SSI_SACCDIS);
+       writel(0x300, base + SSI_SACCEN);
+}
+
+static struct imx_ssi *ac97_ssi;
+
+static void imx_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+               unsigned short val)
+{
+       struct imx_ssi *imx_ssi = ac97_ssi;
+       void __iomem *base = imx_ssi->base;
+       unsigned int lreg;
+       unsigned int lval;
+
+       if (reg > 0x7f)
+               return;
+
+       pr_debug("%s: 0x%02x 0x%04x\n", __func__, reg, val);
+
+       lreg = reg <<  12;
+       writel(lreg, base + SSI_SACADD);
+
+       lval = val << 4;
+       writel(lval , base + SSI_SACDAT);
+
+       writel(SSI_SACNT_DEFAULT | SSI_SACNT_WR, base + SSI_SACNT);
+       udelay(100);
+}
+
+static unsigned short imx_ssi_ac97_read(struct snd_ac97 *ac97,
+               unsigned short reg)
+{
+       struct imx_ssi *imx_ssi = ac97_ssi;
+       void __iomem *base = imx_ssi->base;
+
+       unsigned short val = -1;
+       unsigned int lreg;
+
+       lreg = (reg & 0x7f) <<  12 ;
+       writel(lreg, base + SSI_SACADD);
+       writel(SSI_SACNT_DEFAULT | SSI_SACNT_RD, base + SSI_SACNT);
+
+       udelay(100);
+
+       val = (readl(base + SSI_SACDAT) >> 4) & 0xffff;
+
+       pr_debug("%s: 0x%02x 0x%04x\n", __func__, reg, val);
+
+       return val;
+}
+
+static void imx_ssi_ac97_reset(struct snd_ac97 *ac97)
+{
+       struct imx_ssi *imx_ssi = ac97_ssi;
+
+       if (imx_ssi->ac97_reset)
+               imx_ssi->ac97_reset(ac97);
+}
+
+static void imx_ssi_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+       struct imx_ssi *imx_ssi = ac97_ssi;
+
+       if (imx_ssi->ac97_warm_reset)
+               imx_ssi->ac97_warm_reset(ac97);
+}
+
+struct snd_ac97_bus_ops soc_ac97_ops = {
+       .read           = imx_ssi_ac97_read,
+       .write          = imx_ssi_ac97_write,
+       .reset          = imx_ssi_ac97_reset,
+       .warm_reset     = imx_ssi_ac97_warm_reset
+};
+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;
+
+       ssi = kzalloc(sizeof(*ssi), GFP_KERNEL);
+       if (!ssi)
+               return -ENOMEM;
+
+       if (pdata) {
+               ssi->ac97_reset = pdata->ac97_reset;
+               ssi->ac97_warm_reset = pdata->ac97_warm_reset;
+               ssi->flags = pdata->flags;
+       }
+
+       ssi->irq = platform_get_irq(pdev, 0);
+
+       ssi->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(ssi->clk)) {
+               ret = PTR_ERR(ssi->clk);
+               dev_err(&pdev->dev, "Cannot get the clock: %d\n",
+                       ret);
+               goto failed_clk;
+       }
+       clk_enable(ssi->clk);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               ret = -ENODEV;
+               goto failed_get_resource;
+       }
+
+       if (!request_mem_region(res->start, resource_size(res), DRV_NAME)) {
+               dev_err(&pdev->dev, "request_mem_region failed\n");
+               ret = -EBUSY;
+               goto failed_get_resource;
+       }
+
+       ssi->base = ioremap(res->start, resource_size(res));
+       if (!ssi->base) {
+               dev_err(&pdev->dev, "ioremap failed\n");
+               ret = -ENODEV;
+               goto failed_ioremap;
+       }
+
+       if (ssi->flags & IMX_SSI_USE_AC97) {
+               if (ac97_ssi) {
+                       ret = -EBUSY;
+                       goto failed_ac97;
+               }
+               ac97_ssi = ssi;
+               setup_channel_to_ac97(ssi);
+               memcpy(dai, &imx_ac97_dai, sizeof(imx_ac97_dai));
+       } else
+               memcpy(dai, &imx_ssi_dai, sizeof(imx_ssi_dai));
+
+       writel(0x0, ssi->base + SSI_SIER);
+
+       ssi->dma_params_rx.dma_addr = res->start + SSI_SRX0;
+       ssi->dma_params_tx.dma_addr = res->start + SSI_STX0;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0");
+       if (res)
+               ssi->dma_params_tx.dma = res->start;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx0");
+       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;
+               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);
+
+       ret = snd_soc_register_dai(dai);
+       if (ret) {
+               dev_err(&pdev->dev, "register DAI failed\n");
+               goto failed_register;
+       }
+
+       platform_set_drvdata(pdev, ssi);
+
+       return 0;
+
+failed_register:
+failed_ac97:
+       iounmap(ssi->base);
+failed_ioremap:
+       release_mem_region(res->start, resource_size(res));
+failed_get_resource:
+       clk_disable(ssi->clk);
+       clk_put(ssi->clk);
+failed_clk:
+       kfree(ssi);
+
+       return ret;
+}
+
+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);
+
+       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);
+       clk_put(ssi->clk);
+       kfree(ssi);
+
+       return 0;
+}
+
+static struct platform_driver imx_ssi_driver = {
+       .probe = imx_ssi_probe,
+       .remove = __devexit_p(imx_ssi_remove),
+
+       .driver = {
+               .name = DRV_NAME,
+               .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;
+}
+
+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);
+module_exit(imx_ssi_exit);
+
+/* Module information */
+MODULE_AUTHOR("Sascha Hauer, <s.hauer@pengutronix.de>");
+MODULE_DESCRIPTION("i.MX I2S/ac97 SoC Interface");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/imx/imx-ssi.h b/sound/soc/imx/imx-ssi.h
new file mode 100644 (file)
index 0000000..55f26eb
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * This program is free software; you can 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 _IMX_SSI_H
+#define _IMX_SSI_H
+
+#define SSI_STX0       0x00
+#define SSI_STX1       0x04
+#define SSI_SRX0       0x08
+#define SSI_SRX1       0x0c
+
+#define SSI_SCR                0x10
+#define SSI_SCR_CLK_IST                (1 << 9)
+#define SSI_SCR_CLK_IST_SHIFT  9
+#define SSI_SCR_TCH_EN         (1 << 8)
+#define SSI_SCR_SYS_CLK_EN     (1 << 7)
+#define SSI_SCR_I2S_MODE_NORM  (0 << 5)
+#define SSI_SCR_I2S_MODE_MSTR  (1 << 5)
+#define SSI_SCR_I2S_MODE_SLAVE (2 << 5)
+#define SSI_I2S_MODE_MASK      (3 << 5)
+#define SSI_SCR_SYN            (1 << 4)
+#define SSI_SCR_NET            (1 << 3)
+#define SSI_SCR_RE             (1 << 2)
+#define SSI_SCR_TE             (1 << 1)
+#define SSI_SCR_SSIEN          (1 << 0)
+
+#define SSI_SISR       0x14
+#define SSI_SISR_MASK          ((1 << 19) - 1)
+#define SSI_SISR_CMDAU         (1 << 18)
+#define SSI_SISR_CMDDU         (1 << 17)
+#define SSI_SISR_RXT           (1 << 16)
+#define SSI_SISR_RDR1          (1 << 15)
+#define SSI_SISR_RDR0          (1 << 14)
+#define SSI_SISR_TDE1          (1 << 13)
+#define SSI_SISR_TDE0          (1 << 12)
+#define SSI_SISR_ROE1          (1 << 11)
+#define SSI_SISR_ROE0          (1 << 10)
+#define SSI_SISR_TUE1          (1 << 9)
+#define SSI_SISR_TUE0          (1 << 8)
+#define SSI_SISR_TFS           (1 << 7)
+#define SSI_SISR_RFS           (1 << 6)
+#define SSI_SISR_TLS           (1 << 5)
+#define SSI_SISR_RLS           (1 << 4)
+#define SSI_SISR_RFF1          (1 << 3)
+#define SSI_SISR_RFF0          (1 << 2)
+#define SSI_SISR_TFE1          (1 << 1)
+#define SSI_SISR_TFE0          (1 << 0)
+
+#define SSI_SIER       0x18
+#define SSI_SIER_RDMAE         (1 << 22)
+#define SSI_SIER_RIE           (1 << 21)
+#define SSI_SIER_TDMAE         (1 << 20)
+#define SSI_SIER_TIE           (1 << 19)
+#define SSI_SIER_CMDAU_EN      (1 << 18)
+#define SSI_SIER_CMDDU_EN      (1 << 17)
+#define SSI_SIER_RXT_EN                (1 << 16)
+#define SSI_SIER_RDR1_EN       (1 << 15)
+#define SSI_SIER_RDR0_EN       (1 << 14)
+#define SSI_SIER_TDE1_EN       (1 << 13)
+#define SSI_SIER_TDE0_EN       (1 << 12)
+#define SSI_SIER_ROE1_EN       (1 << 11)
+#define SSI_SIER_ROE0_EN       (1 << 10)
+#define SSI_SIER_TUE1_EN       (1 << 9)
+#define SSI_SIER_TUE0_EN       (1 << 8)
+#define SSI_SIER_TFS_EN                (1 << 7)
+#define SSI_SIER_RFS_EN                (1 << 6)
+#define SSI_SIER_TLS_EN                (1 << 5)
+#define SSI_SIER_RLS_EN                (1 << 4)
+#define SSI_SIER_RFF1_EN       (1 << 3)
+#define SSI_SIER_RFF0_EN       (1 << 2)
+#define SSI_SIER_TFE1_EN       (1 << 1)
+#define SSI_SIER_TFE0_EN       (1 << 0)
+
+#define SSI_STCR       0x1c
+#define SSI_STCR_TXBIT0                (1 << 9)
+#define SSI_STCR_TFEN1         (1 << 8)
+#define SSI_STCR_TFEN0         (1 << 7)
+#define SSI_FIFO_ENABLE_0_SHIFT 7
+#define SSI_STCR_TFDIR         (1 << 6)
+#define SSI_STCR_TXDIR         (1 << 5)
+#define SSI_STCR_TSHFD         (1 << 4)
+#define SSI_STCR_TSCKP         (1 << 3)
+#define SSI_STCR_TFSI          (1 << 2)
+#define SSI_STCR_TFSL          (1 << 1)
+#define SSI_STCR_TEFS          (1 << 0)
+
+#define SSI_SRCR       0x20
+#define SSI_SRCR_RXBIT0                (1 << 9)
+#define SSI_SRCR_RFEN1         (1 << 8)
+#define SSI_SRCR_RFEN0         (1 << 7)
+#define SSI_FIFO_ENABLE_0_SHIFT 7
+#define SSI_SRCR_RFDIR         (1 << 6)
+#define SSI_SRCR_RXDIR         (1 << 5)
+#define SSI_SRCR_RSHFD         (1 << 4)
+#define SSI_SRCR_RSCKP         (1 << 3)
+#define SSI_SRCR_RFSI          (1 << 2)
+#define SSI_SRCR_RFSL          (1 << 1)
+#define SSI_SRCR_REFS          (1 << 0)
+
+#define SSI_SRCCR              0x28
+#define SSI_SRCCR_DIV2         (1 << 18)
+#define SSI_SRCCR_PSR          (1 << 17)
+#define SSI_SRCCR_WL(x)                ((((x) - 2) >> 1) << 13)
+#define SSI_SRCCR_DC(x)                (((x) & 0x1f) << 8)
+#define SSI_SRCCR_PM(x)                (((x) & 0xff) << 0)
+#define SSI_SRCCR_WL_MASK      (0xf << 13)
+#define SSI_SRCCR_DC_MASK      (0x1f << 8)
+#define SSI_SRCCR_PM_MASK      (0xff << 0)
+
+#define SSI_STCCR              0x24
+#define SSI_STCCR_DIV2         (1 << 18)
+#define SSI_STCCR_PSR          (1 << 17)
+#define SSI_STCCR_WL(x)                ((((x) - 2) >> 1) << 13)
+#define SSI_STCCR_DC(x)                (((x) & 0x1f) << 8)
+#define SSI_STCCR_PM(x)                (((x) & 0xff) << 0)
+#define SSI_STCCR_WL_MASK      (0xf << 13)
+#define SSI_STCCR_DC_MASK      (0x1f << 8)
+#define SSI_STCCR_PM_MASK      (0xff << 0)
+
+#define SSI_SFCSR      0x2c
+#define SSI_SFCSR_RFCNT1(x)    (((x) & 0xf) << 28)
+#define SSI_RX_FIFO_1_COUNT_SHIFT 28
+#define SSI_SFCSR_TFCNT1(x)    (((x) & 0xf) << 24)
+#define SSI_TX_FIFO_1_COUNT_SHIFT 24
+#define SSI_SFCSR_RFWM1(x)     (((x) & 0xf) << 20)
+#define SSI_SFCSR_TFWM1(x)     (((x) & 0xf) << 16)
+#define SSI_SFCSR_RFCNT0(x)    (((x) & 0xf) << 12)
+#define SSI_RX_FIFO_0_COUNT_SHIFT 12
+#define SSI_SFCSR_TFCNT0(x)    (((x) & 0xf) <<  8)
+#define SSI_TX_FIFO_0_COUNT_SHIFT 8
+#define SSI_SFCSR_RFWM0(x)     (((x) & 0xf) <<  4)
+#define SSI_SFCSR_TFWM0(x)     (((x) & 0xf) <<  0)
+#define SSI_SFCSR_RFWM0_MASK   (0xf <<  4)
+#define SSI_SFCSR_TFWM0_MASK   (0xf <<  0)
+
+#define SSI_STR                0x30
+#define SSI_STR_TEST           (1 << 15)
+#define SSI_STR_RCK2TCK                (1 << 14)
+#define SSI_STR_RFS2TFS                (1 << 13)
+#define SSI_STR_RXSTATE(x)     (((x) & 0xf) << 8)
+#define SSI_STR_TXD2RXD                (1 <<  7)
+#define SSI_STR_TCK2RCK                (1 <<  6)
+#define SSI_STR_TFS2RFS                (1 <<  5)
+#define SSI_STR_TXSTATE(x)     (((x) & 0xf) << 0)
+
+#define SSI_SOR                0x34
+#define SSI_SOR_CLKOFF         (1 << 6)
+#define SSI_SOR_RX_CLR         (1 << 5)
+#define SSI_SOR_TX_CLR         (1 << 4)
+#define SSI_SOR_INIT           (1 << 3)
+#define SSI_SOR_WAIT(x)                (((x) & 0x3) << 1)
+#define SSI_SOR_WAIT_MASK      (0x3 << 1)
+#define SSI_SOR_SYNRST         (1 << 0)
+
+#define SSI_SACNT      0x38
+#define SSI_SACNT_FRDIV(x)     (((x) & 0x3f) << 5)
+#define SSI_SACNT_WR           (1 << 4)
+#define SSI_SACNT_RD           (1 << 3)
+#define SSI_SACNT_TIF          (1 << 2)
+#define SSI_SACNT_FV           (1 << 1)
+#define SSI_SACNT_AC97EN       (1 << 0)
+
+#define SSI_SACADD     0x3c
+#define SSI_SACDAT     0x40
+#define SSI_SATAG      0x44
+#define SSI_STMSK      0x48
+#define SSI_SRMSK      0x4c
+#define SSI_SACCST     0x50
+#define SSI_SACCEN     0x54
+#define SSI_SACCDIS    0x58
+
+/* SSI clock sources */
+#define IMX_SSP_SYS_CLK                0
+
+/* SSI audio dividers */
+#define IMX_SSI_TX_DIV_2       0
+#define IMX_SSI_TX_DIV_PSR     1
+#define IMX_SSI_TX_DIV_PM      2
+#define IMX_SSI_RX_DIV_2       3
+#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 {
+       int dma;
+       unsigned long dma_addr;
+       int burstsize;
+};
+
+struct imx_ssi {
+       struct platform_device *ac97_dev;
+
+       struct snd_soc_device imx_ac97;
+       struct clk *clk;
+       void __iomem *base;
+       int irq;
+       int fiq_enable;
+       unsigned int offset;
+
+       unsigned int flags;
+
+       void (*ac97_reset) (struct snd_ac97 *ac97);
+       void (*ac97_warm_reset)(struct snd_ac97 *ac97);
+
+       struct imx_pcm_dma_params       dma_params_rx;
+       struct imx_pcm_dma_params       dma_params_tx;
+
+       int enabled;
+};
+
+struct snd_soc_platform *imx_ssi_fiq_init(struct platform_device *pdev,
+               struct imx_ssi *ssi);
+void imx_ssi_fiq_exit(struct platform_device *pdev, struct imx_ssi *ssi);
+struct snd_soc_platform *imx_ssi_dma_mx2_init(struct platform_device *pdev,
+               struct imx_ssi *ssi);
+
+int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma);
+int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
+       struct snd_pcm *pcm);
+void imx_pcm_free(struct snd_pcm *pcm);
+
+/*
+ * Do not change this as the FIQ handler depends on this size
+ */
+#define IMX_SSI_DMABUF_SIZE    (64 * 1024)
+
+#define DMA_RXFIFO_BURST      0x4
+#define DMA_TXFIFO_BURST      0x6
+
+#endif /* _IMX_SSI_H */
diff --git a/sound/soc/imx/mx1_mx2-pcm.c b/sound/soc/imx/mx1_mx2-pcm.c
deleted file mode 100644 (file)
index bffffcd..0000000
+++ /dev/null
@@ -1,488 +0,0 @@
-/*
- * mx1_mx2-pcm.c -- ALSA SoC interface for Freescale i.MX1x, i.MX2x CPUs
- *
- * Copyright 2009 Vista Silicon S.L.
- * Author: Javier Martin
- *         javier.martin@vista-silicon.com
- *
- * Based on mxc-pcm.c by Liam Girdwood.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/dma-mapping.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <asm/dma.h>
-#include <mach/hardware.h>
-#include <mach/dma-mx1-mx2.h>
-
-#include "mx1_mx2-pcm.h"
-
-
-static const struct snd_pcm_hardware mx1_mx2_pcm_hardware = {
-       .info                   = (SNDRV_PCM_INFO_INTERLEAVED |
-                                  SNDRV_PCM_INFO_BLOCK_TRANSFER |
-                                  SNDRV_PCM_INFO_MMAP |
-                                  SNDRV_PCM_INFO_MMAP_VALID),
-       .formats                = SNDRV_PCM_FMTBIT_S16_LE,
-       .buffer_bytes_max       = 32 * 1024,
-       .period_bytes_min       = 64,
-       .period_bytes_max       = 8 * 1024,
-       .periods_min            = 2,
-       .periods_max            = 255,
-       .fifo_size              = 0,
-};
-
-struct mx1_mx2_runtime_data {
-       int dma_ch;
-       int active;
-       unsigned int period;
-       unsigned int periods;
-       int tx_spin;
-       spinlock_t dma_lock;
-       struct mx1_mx2_pcm_dma_params *dma_params;
-};
-
-
-/**
-  * This function stops the current dma transfer for playback
-  * and clears the dma pointers.
-  *
-  * @param     substream       pointer to the structure of the current stream.
-  *
-  */
-static int audio_stop_dma(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct mx1_mx2_runtime_data *prtd = runtime->private_data;
-       unsigned long flags;
-
-       spin_lock_irqsave(&prtd->dma_lock, flags);
-
-       pr_debug("%s\n", __func__);
-
-       prtd->active = 0;
-       prtd->period = 0;
-       prtd->periods = 0;
-
-       /* this stops the dma channel and clears the buffer ptrs */
-
-       imx_dma_disable(prtd->dma_ch);
-
-       spin_unlock_irqrestore(&prtd->dma_lock, flags);
-
-       return 0;
-}
-
-/**
-  * This function is called whenever a new audio block needs to be
-  * transferred to the codec. The function receives the address and the size
-  * of the new block and start a new DMA transfer.
-  *
-  * @param     substream       pointer to the structure of the current stream.
-  *
-  */
-static int dma_new_period(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime =  substream->runtime;
-       struct mx1_mx2_runtime_data *prtd = runtime->private_data;
-       unsigned int dma_size;
-       unsigned int offset;
-       int ret = 0;
-       dma_addr_t mem_addr;
-       unsigned int dev_addr;
-
-       if (prtd->active) {
-               dma_size = frames_to_bytes(runtime, runtime->period_size);
-               offset = dma_size * prtd->period;
-
-               pr_debug("%s: period (%d) out of (%d)\n", __func__,
-                       prtd->period,
-                       runtime->periods);
-               pr_debug("period_size %d frames\n offset %d bytes\n",
-                       (unsigned int)runtime->period_size,
-                       offset);
-               pr_debug("dma_size %d bytes\n", dma_size);
-
-               snd_BUG_ON(dma_size > mx1_mx2_pcm_hardware.period_bytes_max);
-
-               mem_addr = (dma_addr_t)(runtime->dma_addr + offset);
-               dev_addr = prtd->dma_params->per_address;
-               pr_debug("%s: mem_addr is %x\n dev_addr is %x\n",
-                                __func__, mem_addr, dev_addr);
-
-               ret = imx_dma_setup_single(prtd->dma_ch, mem_addr,
-                                       dma_size, dev_addr,
-                                       prtd->dma_params->transfer_type);
-               if (ret < 0) {
-                       printk(KERN_ERR "Error %d configuring DMA\n", ret);
-                       return ret;
-               }
-               imx_dma_enable(prtd->dma_ch);
-
-               pr_debug("%s: transfer enabled\nmem_addr = %x\n",
-                       __func__, (unsigned int) mem_addr);
-               pr_debug("dev_addr = %x\ndma_size = %d\n",
-                       (unsigned int) dev_addr, dma_size);
-
-               prtd->tx_spin = 1; /* FGA little trick to retrieve DMA pos */
-               prtd->period++;
-               prtd->period %= runtime->periods;
-    }
-       return ret;
-}
-
-
-/**
-  * This is a callback which will be called
-  * when a TX transfer finishes. The call occurs
-  * in interrupt context.
-  *
-  * @param     dat     pointer to the structure of the current stream.
-  *
-  */
-static void audio_dma_irq(int channel, void *data)
-{
-       struct snd_pcm_substream *substream;
-       struct snd_pcm_runtime *runtime;
-       struct mx1_mx2_runtime_data *prtd;
-       unsigned int dma_size;
-       unsigned int previous_period;
-       unsigned int offset;
-
-       substream = data;
-       runtime = substream->runtime;
-       prtd = runtime->private_data;
-       previous_period  = prtd->periods;
-       dma_size = frames_to_bytes(runtime, runtime->period_size);
-       offset = dma_size * previous_period;
-
-       prtd->tx_spin = 0;
-       prtd->periods++;
-       prtd->periods %= runtime->periods;
-
-       pr_debug("%s: irq per %d offset %x\n", __func__, prtd->periods, offset);
-
-       /*
-         * If we are getting a callback for an active stream then we inform
-         * the PCM middle layer we've finished a period
-         */
-       if (prtd->active)
-               snd_pcm_period_elapsed(substream);
-
-       /*
-         * Trig next DMA transfer
-         */
-       dma_new_period(substream);
-}
-
-/**
-  * This function configures the hardware to allow audio
-  * playback operations. It is called by ALSA framework.
-  *
-  * @param     substream       pointer to the structure of the current stream.
-  *
-  * @return              0 on success, -1 otherwise.
-  */
-static int
-snd_mx1_mx2_prepare(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime =  substream->runtime;
-       struct mx1_mx2_runtime_data *prtd = runtime->private_data;
-
-       prtd->period = 0;
-       prtd->periods = 0;
-
-       return 0;
-}
-
-static int mx1_mx2_pcm_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *hw_params)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       int ret;
-
-       ret = snd_pcm_lib_malloc_pages(substream,
-                                       params_buffer_bytes(hw_params));
-       if (ret < 0) {
-               printk(KERN_ERR "%s: Error %d failed to malloc pcm pages \n",
-               __func__, ret);
-               return ret;
-       }
-
-       pr_debug("%s: snd_imx1_mx2_audio_hw_params runtime->dma_addr 0x(%x)\n",
-               __func__, (unsigned int)runtime->dma_addr);
-       pr_debug("%s: snd_imx1_mx2_audio_hw_params runtime->dma_area 0x(%x)\n",
-               __func__, (unsigned int)runtime->dma_area);
-       pr_debug("%s: snd_imx1_mx2_audio_hw_params runtime->dma_bytes 0x(%x)\n",
-               __func__, (unsigned int)runtime->dma_bytes);
-
-       return ret;
-}
-
-static int mx1_mx2_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct mx1_mx2_runtime_data *prtd = runtime->private_data;
-
-       imx_dma_free(prtd->dma_ch);
-
-       snd_pcm_lib_free_pages(substream);
-
-       return 0;
-}
-
-static int mx1_mx2_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-       struct mx1_mx2_runtime_data *prtd = substream->runtime->private_data;
-       int ret = 0;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               prtd->tx_spin = 0;
-               /* requested stream startup */
-               prtd->active = 1;
-               pr_debug("%s: starting dma_new_period\n", __func__);
-               ret = dma_new_period(substream);
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-               /* requested stream shutdown */
-               pr_debug("%s: stopping dma transfer\n", __func__);
-               ret = audio_stop_dma(substream);
-               break;
-       default:
-               ret = -EINVAL;
-               break;
-       }
-
-       return ret;
-}
-
-static snd_pcm_uframes_t
-mx1_mx2_pcm_pointer(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct mx1_mx2_runtime_data *prtd = runtime->private_data;
-       unsigned int offset = 0;
-
-       /* tx_spin value is used here to check if a transfer is active */
-       if (prtd->tx_spin) {
-               offset = (runtime->period_size * (prtd->periods)) +
-                                               (runtime->period_size >> 1);
-               if (offset >= runtime->buffer_size)
-                       offset = runtime->period_size >> 1;
-       } else {
-               offset = (runtime->period_size * (prtd->periods));
-               if (offset >= runtime->buffer_size)
-                       offset = 0;
-       }
-       pr_debug("%s: pointer offset %x\n", __func__, offset);
-
-       return offset;
-}
-
-static int mx1_mx2_pcm_open(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct mx1_mx2_runtime_data *prtd;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct mx1_mx2_pcm_dma_params *dma_data = rtd->dai->cpu_dai->dma_data;
-       int ret;
-
-       snd_soc_set_runtime_hwparams(substream, &mx1_mx2_pcm_hardware);
-
-       ret = snd_pcm_hw_constraint_integer(runtime,
-                                       SNDRV_PCM_HW_PARAM_PERIODS);
-       if (ret < 0)
-               return ret;
-
-       prtd = kzalloc(sizeof(struct mx1_mx2_runtime_data), GFP_KERNEL);
-       if (prtd == NULL) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       runtime->private_data = prtd;
-
-       if (!dma_data)
-               return -ENODEV;
-
-       prtd->dma_params = dma_data;
-
-       pr_debug("%s: Requesting dma channel (%s)\n", __func__,
-                                               prtd->dma_params->name);
-       ret = imx_dma_request_by_prio(prtd->dma_params->name, DMA_PRIO_HIGH);
-       if (ret < 0) {
-               printk(KERN_ERR "Error %d requesting dma channel\n", ret);
-               return ret;
-       }
-       prtd->dma_ch = ret;
-       imx_dma_config_burstlen(prtd->dma_ch,
-                               prtd->dma_params->watermark_level);
-
-       ret = imx_dma_config_channel(prtd->dma_ch,
-                       prtd->dma_params->per_config,
-                       prtd->dma_params->mem_config,
-                       prtd->dma_params->event_id, 0);
-
-       if (ret) {
-               pr_debug(KERN_ERR "Error %d configuring dma channel %d\n",
-                       ret, prtd->dma_ch);
-               return ret;
-       }
-
-       pr_debug("%s: Setting tx dma callback function\n", __func__);
-       ret = imx_dma_setup_handlers(prtd->dma_ch,
-                               audio_dma_irq, NULL,
-                               (void *)substream);
-       if (ret < 0) {
-               printk(KERN_ERR "Error %d setting dma callback function\n", ret);
-               return ret;
-       }
-       return 0;
-
- out:
-       return ret;
-}
-
-static int mx1_mx2_pcm_close(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct mx1_mx2_runtime_data *prtd = runtime->private_data;
-
-       kfree(prtd);
-
-       return 0;
-}
-
-static int mx1_mx2_pcm_mmap(struct snd_pcm_substream *substream,
-                               struct vm_area_struct *vma)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       return dma_mmap_writecombine(substream->pcm->card->dev, vma,
-                                    runtime->dma_area,
-                                    runtime->dma_addr,
-                                    runtime->dma_bytes);
-}
-
-static struct snd_pcm_ops mx1_mx2_pcm_ops = {
-       .open           = mx1_mx2_pcm_open,
-       .close          = mx1_mx2_pcm_close,
-       .ioctl          = snd_pcm_lib_ioctl,
-       .hw_params      = mx1_mx2_pcm_hw_params,
-       .hw_free        = mx1_mx2_pcm_hw_free,
-       .prepare        = snd_mx1_mx2_prepare,
-       .trigger        = mx1_mx2_pcm_trigger,
-       .pointer        = mx1_mx2_pcm_pointer,
-       .mmap           = mx1_mx2_pcm_mmap,
-};
-
-static u64 mx1_mx2_pcm_dmamask = 0xffffffff;
-
-static int mx1_mx2_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
-{
-       struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-       struct snd_dma_buffer *buf = &substream->dma_buffer;
-       size_t size = mx1_mx2_pcm_hardware.buffer_bytes_max;
-       buf->dev.type = SNDRV_DMA_TYPE_DEV;
-       buf->dev.dev = pcm->card->dev;
-       buf->private_data = NULL;
-
-       /* Reserve uncached-buffered memory area for DMA */
-       buf->area = dma_alloc_writecombine(pcm->card->dev, size,
-                                          &buf->addr, GFP_KERNEL);
-
-       pr_debug("%s: preallocate_dma_buffer: area=%p, addr=%p, size=%d\n",
-               __func__, (void *) buf->area, (void *) buf->addr, size);
-
-       if (!buf->area)
-               return -ENOMEM;
-
-       buf->bytes = size;
-       return 0;
-}
-
-static void mx1_mx2_pcm_free_dma_buffers(struct snd_pcm *pcm)
-{
-       struct snd_pcm_substream *substream;
-       struct snd_dma_buffer *buf;
-       int stream;
-
-       for (stream = 0; stream < 2; stream++) {
-               substream = pcm->streams[stream].substream;
-               if (!substream)
-                       continue;
-
-               buf = &substream->dma_buffer;
-               if (!buf->area)
-                       continue;
-
-               dma_free_writecombine(pcm->card->dev, buf->bytes,
-                                     buf->area, buf->addr);
-               buf->area = NULL;
-       }
-}
-
-static int mx1_mx2_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
-       struct snd_pcm *pcm)
-{
-       int ret = 0;
-
-       if (!card->dev->dma_mask)
-               card->dev->dma_mask = &mx1_mx2_pcm_dmamask;
-       if (!card->dev->coherent_dma_mask)
-               card->dev->coherent_dma_mask = 0xffffffff;
-
-       if (dai->playback.channels_min) {
-               ret = mx1_mx2_pcm_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_PLAYBACK);
-               pr_debug("%s: preallocate playback buffer\n", __func__);
-               if (ret)
-                       goto out;
-       }
-
-       if (dai->capture.channels_min) {
-               ret = mx1_mx2_pcm_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_CAPTURE);
-               pr_debug("%s: preallocate capture buffer\n", __func__);
-               if (ret)
-                       goto out;
-       }
- out:
-       return ret;
-}
-
-struct snd_soc_platform mx1_mx2_soc_platform = {
-       .name           = "mx1_mx2-audio",
-       .pcm_ops        = &mx1_mx2_pcm_ops,
-       .pcm_new        = mx1_mx2_pcm_new,
-       .pcm_free       = mx1_mx2_pcm_free_dma_buffers,
-};
-EXPORT_SYMBOL_GPL(mx1_mx2_soc_platform);
-
-static int __init mx1_mx2_soc_platform_init(void)
-{
-       return snd_soc_register_platform(&mx1_mx2_soc_platform);
-}
-module_init(mx1_mx2_soc_platform_init);
-
-static void __exit mx1_mx2_soc_platform_exit(void)
-{
-       snd_soc_unregister_platform(&mx1_mx2_soc_platform);
-}
-module_exit(mx1_mx2_soc_platform_exit);
-
-MODULE_AUTHOR("Javier Martin, javier.martin@vista-silicon.com");
-MODULE_DESCRIPTION("Freescale i.MX2x, i.MX1x PCM DMA module");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/imx/mx1_mx2-pcm.h b/sound/soc/imx/mx1_mx2-pcm.h
deleted file mode 100644 (file)
index 2e52810..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * mx1_mx2-pcm.h :- ASoC platform header for Freescale i.MX1x, i.MX2x
- *
- * This program is free software; you can 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 _MX1_MX2_PCM_H
-#define _MX1_MX2_PCM_H
-
-/* DMA information for mx1_mx2 platforms */
-struct mx1_mx2_pcm_dma_params {
-       char *name;                     /* stream identifier */
-       unsigned int transfer_type;     /* READ or WRITE DMA transfer */
-       dma_addr_t per_address;         /* physical address of SSI fifo */
-       int event_id;                   /* fixed DMA number for SSI fifo */
-       int watermark_level;            /* SSI fifo watermark level */
-       int per_config;                 /* DMA Config flags for peripheral */
-       int mem_config;                 /* DMA Config flags for RAM */
- };
-
-/* platform data */
-extern struct snd_soc_platform mx1_mx2_soc_platform;
-
-#endif
diff --git a/sound/soc/imx/mx27vis_wm8974.c b/sound/soc/imx/mx27vis_wm8974.c
deleted file mode 100644 (file)
index 07d2a24..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * mx27vis_wm8974.c  --  SoC audio for mx27vis
- *
- * Copyright 2009 Vista Silicon S.L.
- * Author: Javier Martin
- *         javier.martin@vista-silicon.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/device.h>
-#include <linux/i2c.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-
-
-#include "../codecs/wm8974.h"
-#include "mx1_mx2-pcm.h"
-#include "mxc-ssi.h"
-#include <mach/gpio.h>
-#include <mach/iomux.h>
-
-#define IGNORED_ARG 0
-
-
-static struct snd_soc_card mx27vis;
-
-/**
-  * This function connects SSI1 (HPCR1) as slave to
-  * SSI1 external signals (PPCR1)
-  * As slave, HPCR1 must set TFSDIR and TCLKDIR as inputs from
-  * port 4
-  */
-void audmux_connect_1_4(void)
-{
-       pr_debug("AUDMUX: normal operation mode\n");
-       /* Reset HPCR1 and PPCR1 */
-
-       DAM_HPCR1 = 0x00000000;
-       DAM_PPCR1 = 0x00000000;
-
-       /* set to synchronous */
-       DAM_HPCR1 |= AUDMUX_HPCR_SYN;
-       DAM_PPCR1 |= AUDMUX_PPCR_SYN;
-
-
-       /* set Rx sources 1 <--> 4 */
-       DAM_HPCR1 |= AUDMUX_HPCR_RXDSEL(3); /* port 4 */
-       DAM_PPCR1 |= AUDMUX_PPCR_RXDSEL(0); /* port 1 */
-
-       /* set Tx frame and Clock direction and source  4 --> 1 output */
-       DAM_HPCR1 |= AUDMUX_HPCR_TFSDIR | AUDMUX_HPCR_TCLKDIR;
-       DAM_HPCR1 |= AUDMUX_HPCR_TFCSEL(3); /* TxDS and TxCclk from port 4 */
-
-       return;
-}
-
-static int mx27vis_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;
-       unsigned int pll_out = 0, bclk = 0, fmt = 0, mclk = 0;
-       int ret = 0;
-
-       /*
-        * The WM8974 is better at generating accurate audio clocks than the
-        * MX27 SSI controller, so we will use it as master when we can.
-        */
-       switch (params_rate(params)) {
-       case 8000:
-               fmt = SND_SOC_DAIFMT_CBM_CFM;
-               mclk = WM8974_MCLKDIV_12;
-               pll_out = 24576000;
-               break;
-       case 16000:
-               fmt = SND_SOC_DAIFMT_CBM_CFM;
-               pll_out = 12288000;
-               break;
-       case 48000:
-               fmt = SND_SOC_DAIFMT_CBM_CFM;
-               bclk = WM8974_BCLKDIV_4;
-               pll_out = 12288000;
-               break;
-       case 96000:
-               fmt = SND_SOC_DAIFMT_CBM_CFM;
-               bclk = WM8974_BCLKDIV_2;
-               pll_out = 12288000;
-               break;
-       case 11025:
-               fmt = SND_SOC_DAIFMT_CBM_CFM;
-               bclk = WM8974_BCLKDIV_16;
-               pll_out = 11289600;
-               break;
-       case 22050:
-               fmt = SND_SOC_DAIFMT_CBM_CFM;
-               bclk = WM8974_BCLKDIV_8;
-               pll_out = 11289600;
-               break;
-       case 44100:
-               fmt = SND_SOC_DAIFMT_CBM_CFM;
-               bclk = WM8974_BCLKDIV_4;
-               mclk = WM8974_MCLKDIV_2;
-               pll_out = 11289600;
-               break;
-       case 88200:
-               fmt = SND_SOC_DAIFMT_CBM_CFM;
-               bclk = WM8974_BCLKDIV_2;
-               pll_out = 11289600;
-               break;
-       }
-
-       /* set codec DAI configuration */
-       ret = codec_dai->ops->set_fmt(codec_dai,
-               SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF |
-               SND_SOC_DAIFMT_SYNC | fmt);
-       if (ret < 0) {
-               printk(KERN_ERR "Error from codec DAI configuration\n");
-               return ret;
-       }
-
-       /* set cpu DAI configuration */
-       ret = cpu_dai->ops->set_fmt(cpu_dai,
-               SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-               SND_SOC_DAIFMT_SYNC | fmt);
-       if (ret < 0) {
-               printk(KERN_ERR "Error from cpu DAI configuration\n");
-               return ret;
-       }
-
-       /* Put DC field of STCCR to 1 (not zero) */
-       ret = cpu_dai->ops->set_tdm_slot(cpu_dai, 0, 2);
-
-       /* set the SSI system clock as input */
-       ret = cpu_dai->ops->set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0,
-               SND_SOC_CLOCK_IN);
-       if (ret < 0) {
-               printk(KERN_ERR "Error when setting system SSI clk\n");
-               return ret;
-       }
-
-       /* set codec BCLK division for sample rate */
-       ret = codec_dai->ops->set_clkdiv(codec_dai, WM8974_BCLKDIV, bclk);
-       if (ret < 0) {
-               printk(KERN_ERR "Error when setting BCLK division\n");
-               return ret;
-       }
-
-
-       /* codec PLL input is 25 MHz */
-       ret = codec_dai->ops->set_pll(codec_dai, IGNORED_ARG, IGNORED_ARG,
-                                       25000000, pll_out);
-       if (ret < 0) {
-               printk(KERN_ERR "Error when setting PLL input\n");
-               return ret;
-       }
-
-       /*set codec MCLK division for sample rate */
-       ret = codec_dai->ops->set_clkdiv(codec_dai, WM8974_MCLKDIV, mclk);
-       if (ret < 0) {
-               printk(KERN_ERR "Error when setting MCLK division\n");
-               return ret;
-       }
-
-       return 0;
-}
-
-static int mx27vis_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;
-
-       /* disable the PLL */
-       return codec_dai->ops->set_pll(codec_dai, IGNORED_ARG, IGNORED_ARG,
-                                      0, 0);
-}
-
-/*
- * mx27vis WM8974 HiFi DAI opserations.
- */
-static struct snd_soc_ops mx27vis_hifi_ops = {
-       .hw_params = mx27vis_hifi_hw_params,
-       .hw_free = mx27vis_hifi_hw_free,
-};
-
-
-static int mx27vis_suspend(struct platform_device *pdev, pm_message_t state)
-{
-       return 0;
-}
-
-static int mx27vis_resume(struct platform_device *pdev)
-{
-       return 0;
-}
-
-static int mx27vis_probe(struct platform_device *pdev)
-{
-       int ret = 0;
-
-       ret = get_ssi_clk(0, &pdev->dev);
-
-       if (ret < 0) {
-               printk(KERN_ERR "%s: cant get ssi clock\n", __func__);
-               return ret;
-       }
-
-
-       return 0;
-}
-
-static int mx27vis_remove(struct platform_device *pdev)
-{
-       put_ssi_clk(0);
-       return 0;
-}
-
-static struct snd_soc_dai_link mx27vis_dai[] = {
-{ /* Hifi Playback*/
-       .name = "WM8974",
-       .stream_name = "WM8974 HiFi",
-       .cpu_dai = &imx_ssi_pcm_dai[0],
-       .codec_dai = &wm8974_dai,
-       .ops = &mx27vis_hifi_ops,
-},
-};
-
-static struct snd_soc_card mx27vis = {
-       .name = "mx27vis",
-       .platform = &mx1_mx2_soc_platform,
-       .probe = mx27vis_probe,
-       .remove = mx27vis_remove,
-       .suspend_pre = mx27vis_suspend,
-       .resume_post = mx27vis_resume,
-       .dai_link = mx27vis_dai,
-       .num_links = ARRAY_SIZE(mx27vis_dai),
-};
-
-static struct snd_soc_device mx27vis_snd_devdata = {
-       .card = &mx27vis,
-       .codec_dev = &soc_codec_dev_wm8974,
-};
-
-static struct platform_device *mx27vis_snd_device;
-
-/* Temporal definition of board specific behaviour */
-void gpio_ssi_active(int ssi_num)
-{
-       int ret = 0;
-
-       unsigned int ssi1_pins[] = {
-               PC20_PF_SSI1_FS,
-               PC21_PF_SSI1_RXD,
-               PC22_PF_SSI1_TXD,
-               PC23_PF_SSI1_CLK,
-       };
-       unsigned int ssi2_pins[] = {
-               PC24_PF_SSI2_FS,
-               PC25_PF_SSI2_RXD,
-               PC26_PF_SSI2_TXD,
-               PC27_PF_SSI2_CLK,
-       };
-       if (ssi_num == 0)
-               ret = mxc_gpio_setup_multiple_pins(ssi1_pins,
-                               ARRAY_SIZE(ssi1_pins), "USB OTG");
-       else
-               ret = mxc_gpio_setup_multiple_pins(ssi2_pins,
-                               ARRAY_SIZE(ssi2_pins), "USB OTG");
-       if (ret)
-               printk(KERN_ERR "Error requesting ssi %x pins\n", ssi_num);
-}
-
-
-static int __init mx27vis_init(void)
-{
-       int ret;
-
-       mx27vis_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!mx27vis_snd_device)
-               return -ENOMEM;
-
-       platform_set_drvdata(mx27vis_snd_device, &mx27vis_snd_devdata);
-       mx27vis_snd_devdata.dev = &mx27vis_snd_device->dev;
-       ret = platform_device_add(mx27vis_snd_device);
-
-       if (ret) {
-               printk(KERN_ERR "ASoC: Platform device allocation failed\n");
-               platform_device_put(mx27vis_snd_device);
-       }
-
-       /* WM8974 uses SSI1 (HPCR1) via AUDMUX port 4 for audio (PPCR1) */
-       gpio_ssi_active(0);
-       audmux_connect_1_4();
-
-       return ret;
-}
-
-static void __exit mx27vis_exit(void)
-{
-       /* We should call some "ssi_gpio_inactive()" properly */
-}
-
-module_init(mx27vis_init);
-module_exit(mx27vis_exit);
-
-
-MODULE_AUTHOR("Javier Martin, javier.martin@vista-silicon.com");
-MODULE_DESCRIPTION("ALSA SoC WM8974 mx27vis");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/imx/mxc-ssi.c b/sound/soc/imx/mxc-ssi.c
deleted file mode 100644 (file)
index ccdefe6..0000000
+++ /dev/null
@@ -1,860 +0,0 @@
-/*
- * mxc-ssi.c  --  SSI driver for Freescale IMX
- *
- * Copyright 2006 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
- *
- *  Based on mxc-alsa-mc13783 (C) 2006 Freescale.
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
- * TODO:
- *   Need to rework SSI register defs when new defs go into mainline.
- *   Add support for TDM and FIFO 1.
- *   Add support for i.mx3x DMA interface.
- *
- */
-
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/dma-mapping.h>
-#include <linux/clk.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <mach/dma-mx1-mx2.h>
-#include <asm/mach-types.h>
-
-#include "mxc-ssi.h"
-#include "mx1_mx2-pcm.h"
-
-#define SSI1_PORT      0
-#define SSI2_PORT      1
-
-static int ssi_active[2] = {0, 0};
-
-/* DMA information for mx1_mx2 platforms */
-static struct mx1_mx2_pcm_dma_params imx_ssi1_pcm_stereo_out0 = {
-       .name                   = "SSI1 PCM Stereo out 0",
-       .transfer_type = DMA_MODE_WRITE,
-       .per_address = SSI1_BASE_ADDR + STX0,
-       .event_id = DMA_REQ_SSI1_TX0,
-       .watermark_level = TXFIFO_WATERMARK,
-       .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
-       .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
-};
-
-static struct mx1_mx2_pcm_dma_params imx_ssi1_pcm_stereo_out1 = {
-       .name                   = "SSI1 PCM Stereo out 1",
-       .transfer_type = DMA_MODE_WRITE,
-       .per_address = SSI1_BASE_ADDR + STX1,
-       .event_id = DMA_REQ_SSI1_TX1,
-       .watermark_level = TXFIFO_WATERMARK,
-       .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
-       .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
-};
-
-static struct mx1_mx2_pcm_dma_params imx_ssi1_pcm_stereo_in0 = {
-       .name                   = "SSI1 PCM Stereo in 0",
-       .transfer_type = DMA_MODE_READ,
-       .per_address = SSI1_BASE_ADDR + SRX0,
-       .event_id = DMA_REQ_SSI1_RX0,
-       .watermark_level = RXFIFO_WATERMARK,
-       .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
-       .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
-};
-
-static struct mx1_mx2_pcm_dma_params imx_ssi1_pcm_stereo_in1 = {
-       .name                   = "SSI1 PCM Stereo in 1",
-       .transfer_type = DMA_MODE_READ,
-       .per_address = SSI1_BASE_ADDR + SRX1,
-       .event_id = DMA_REQ_SSI1_RX1,
-       .watermark_level = RXFIFO_WATERMARK,
-       .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
-       .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
-};
-
-static struct mx1_mx2_pcm_dma_params imx_ssi2_pcm_stereo_out0 = {
-       .name                   = "SSI2 PCM Stereo out 0",
-       .transfer_type = DMA_MODE_WRITE,
-       .per_address = SSI2_BASE_ADDR + STX0,
-       .event_id = DMA_REQ_SSI2_TX0,
-       .watermark_level = TXFIFO_WATERMARK,
-       .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
-       .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
-};
-
-static struct mx1_mx2_pcm_dma_params imx_ssi2_pcm_stereo_out1 = {
-       .name                   = "SSI2 PCM Stereo out 1",
-       .transfer_type = DMA_MODE_WRITE,
-       .per_address = SSI2_BASE_ADDR + STX1,
-       .event_id = DMA_REQ_SSI2_TX1,
-       .watermark_level = TXFIFO_WATERMARK,
-       .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
-       .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
-};
-
-static struct mx1_mx2_pcm_dma_params imx_ssi2_pcm_stereo_in0 = {
-       .name                   = "SSI2 PCM Stereo in 0",
-       .transfer_type = DMA_MODE_READ,
-       .per_address = SSI2_BASE_ADDR + SRX0,
-       .event_id = DMA_REQ_SSI2_RX0,
-       .watermark_level = RXFIFO_WATERMARK,
-       .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
-       .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
-};
-
-static struct mx1_mx2_pcm_dma_params imx_ssi2_pcm_stereo_in1 = {
-       .name                   = "SSI2 PCM Stereo in 1",
-       .transfer_type = DMA_MODE_READ,
-       .per_address = SSI2_BASE_ADDR + SRX1,
-       .event_id = DMA_REQ_SSI2_RX1,
-       .watermark_level = RXFIFO_WATERMARK,
-       .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
-       .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
-};
-
-static struct clk *ssi_clk0, *ssi_clk1;
-
-int get_ssi_clk(int ssi, struct device *dev)
-{
-       switch (ssi) {
-       case 0:
-               ssi_clk0 = clk_get(dev, "ssi1");
-               if (IS_ERR(ssi_clk0))
-                       return PTR_ERR(ssi_clk0);
-               return 0;
-       case 1:
-               ssi_clk1 = clk_get(dev, "ssi2");
-               if (IS_ERR(ssi_clk1))
-                       return PTR_ERR(ssi_clk1);
-               return 0;
-       default:
-               return -EINVAL;
-       }
-}
-EXPORT_SYMBOL(get_ssi_clk);
-
-void put_ssi_clk(int ssi)
-{
-       switch (ssi) {
-       case 0:
-               clk_put(ssi_clk0);
-               ssi_clk0 = NULL;
-               break;
-       case 1:
-               clk_put(ssi_clk1);
-               ssi_clk1 = NULL;
-               break;
-       }
-}
-EXPORT_SYMBOL(put_ssi_clk);
-
-/*
- * SSI system clock configuration.
- * Should only be called when port is inactive (i.e. SSIEN = 0).
- */
-static int imx_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
-       int clk_id, unsigned int freq, int dir)
-{
-       u32 scr;
-
-       if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
-               scr = SSI1_SCR;
-               pr_debug("%s: SCR for SSI1 is %x\n", __func__, scr);
-       } else {
-               scr = SSI2_SCR;
-               pr_debug("%s: SCR for SSI2 is %x\n", __func__, scr);
-       }
-
-       if (scr & SSI_SCR_SSIEN) {
-               printk(KERN_WARNING "Warning ssi already enabled\n");
-               return 0;
-       }
-
-       switch (clk_id) {
-       case IMX_SSP_SYS_CLK:
-               if (dir == SND_SOC_CLOCK_OUT) {
-                       scr |= SSI_SCR_SYS_CLK_EN;
-                       pr_debug("%s: clk of is output\n", __func__);
-               } else {
-                       scr &= ~SSI_SCR_SYS_CLK_EN;
-                       pr_debug("%s: clk of is input\n", __func__);
-               }
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
-               pr_debug("%s: writeback of SSI1_SCR\n", __func__);
-               SSI1_SCR = scr;
-       } else {
-               pr_debug("%s: writeback of SSI2_SCR\n", __func__);
-               SSI2_SCR = scr;
-       }
-
-       return 0;
-}
-
-/*
- * SSI Clock dividers
- * Should only be called when port is inactive (i.e. SSIEN = 0).
- */
-static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
-       int div_id, int div)
-{
-       u32 stccr, srccr;
-
-       pr_debug("%s\n", __func__);
-       if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
-               if (SSI1_SCR & SSI_SCR_SSIEN)
-                       return 0;
-               srccr = SSI1_STCCR;
-               stccr = SSI1_STCCR;
-       } else {
-               if (SSI2_SCR & SSI_SCR_SSIEN)
-                       return 0;
-               srccr = SSI2_STCCR;
-               stccr = SSI2_STCCR;
-       }
-
-       switch (div_id) {
-       case IMX_SSI_TX_DIV_2:
-               stccr &= ~SSI_STCCR_DIV2;
-               stccr |= div;
-               break;
-       case IMX_SSI_TX_DIV_PSR:
-               stccr &= ~SSI_STCCR_PSR;
-               stccr |= div;
-               break;
-       case IMX_SSI_TX_DIV_PM:
-               stccr &= ~0xff;
-               stccr |= SSI_STCCR_PM(div);
-               break;
-       case IMX_SSI_RX_DIV_2:
-               stccr &= ~SSI_STCCR_DIV2;
-               stccr |= div;
-               break;
-       case IMX_SSI_RX_DIV_PSR:
-               stccr &= ~SSI_STCCR_PSR;
-               stccr |= div;
-               break;
-       case IMX_SSI_RX_DIV_PM:
-               stccr &= ~0xff;
-               stccr |= SSI_STCCR_PM(div);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
-               SSI1_STCCR = stccr;
-               SSI1_SRCCR = srccr;
-       } else {
-               SSI2_STCCR = stccr;
-               SSI2_SRCCR = srccr;
-       }
-       return 0;
-}
-
-/*
- * SSI Network Mode or TDM slots configuration.
- * Should only be called when port is inactive (i.e. SSIEN = 0).
- */
-static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
-       unsigned int mask, int slots)
-{
-       u32 stmsk, srmsk, stccr;
-
-       if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
-               if (SSI1_SCR & SSI_SCR_SSIEN) {
-                       printk(KERN_WARNING "Warning ssi already enabled\n");
-                       return 0;
-               }
-               stccr = SSI1_STCCR;
-       } else {
-               if (SSI2_SCR & SSI_SCR_SSIEN) {
-                       printk(KERN_WARNING "Warning ssi already enabled\n");
-                       return 0;
-               }
-               stccr = SSI2_STCCR;
-       }
-
-       stmsk = srmsk = mask;
-       stccr &= ~SSI_STCCR_DC_MASK;
-       stccr |= SSI_STCCR_DC(slots - 1);
-
-       if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
-               SSI1_STMSK = stmsk;
-               SSI1_SRMSK = srmsk;
-               SSI1_SRCCR = SSI1_STCCR = stccr;
-       } else {
-               SSI2_STMSK = stmsk;
-               SSI2_SRMSK = srmsk;
-               SSI2_SRCCR = SSI2_STCCR = stccr;
-       }
-
-       return 0;
-}
-
-/*
- * SSI DAI format configuration.
- * Should only be called when port is inactive (i.e. SSIEN = 0).
- * Note: We don't use the I2S modes but instead manually configure the
- * SSI for I2S.
- */
-static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai,
-               unsigned int fmt)
-{
-       u32 stcr = 0, srcr = 0, scr;
-
-       /*
-        * This is done to avoid this function to modify
-        * previous set values in stcr
-        */
-       stcr = SSI1_STCR;
-
-       if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2)
-               scr = SSI1_SCR & ~(SSI_SCR_SYN | SSI_SCR_NET);
-       else
-               scr = SSI2_SCR & ~(SSI_SCR_SYN | SSI_SCR_NET);
-
-       if (scr & SSI_SCR_SSIEN) {
-               printk(KERN_WARNING "Warning ssi already enabled\n");
-               return 0;
-       }
-
-       /* DAI mode */
-       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-       case SND_SOC_DAIFMT_I2S:
-               /* data on rising edge of bclk, frame low 1clk before data */
-               stcr |= SSI_STCR_TFSI | SSI_STCR_TEFS | SSI_STCR_TXBIT0;
-               srcr |= SSI_SRCR_RFSI | SSI_SRCR_REFS | SSI_SRCR_RXBIT0;
-               break;
-       case SND_SOC_DAIFMT_LEFT_J:
-               /* data on rising edge of bclk, frame high with data */
-               stcr |= SSI_STCR_TXBIT0;
-               srcr |= SSI_SRCR_RXBIT0;
-               break;
-       case SND_SOC_DAIFMT_DSP_B:
-               /* data on rising edge of bclk, frame high with data */
-               stcr |= SSI_STCR_TFSL;
-               srcr |= SSI_SRCR_RFSL;
-               break;
-       case SND_SOC_DAIFMT_DSP_A:
-               /* data on rising edge of bclk, frame high 1clk before data */
-               stcr |= SSI_STCR_TFSL | SSI_STCR_TEFS;
-               srcr |= SSI_SRCR_RFSL | SSI_SRCR_REFS;
-               break;
-       }
-
-       /* DAI clock inversion */
-       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
-       case SND_SOC_DAIFMT_IB_IF:
-               stcr |= SSI_STCR_TFSI;
-               stcr &= ~SSI_STCR_TSCKP;
-               srcr |= SSI_SRCR_RFSI;
-               srcr &= ~SSI_SRCR_RSCKP;
-               break;
-       case SND_SOC_DAIFMT_IB_NF:
-               stcr &= ~(SSI_STCR_TSCKP | SSI_STCR_TFSI);
-               srcr &= ~(SSI_SRCR_RSCKP | SSI_SRCR_RFSI);
-               break;
-       case SND_SOC_DAIFMT_NB_IF:
-               stcr |= SSI_STCR_TFSI | SSI_STCR_TSCKP;
-               srcr |= SSI_SRCR_RFSI | SSI_SRCR_RSCKP;
-               break;
-       case SND_SOC_DAIFMT_NB_NF:
-               stcr &= ~SSI_STCR_TFSI;
-               stcr |= SSI_STCR_TSCKP;
-               srcr &= ~SSI_SRCR_RFSI;
-               srcr |= SSI_SRCR_RSCKP;
-               break;
-       }
-
-       /* DAI clock master masks */
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
-               stcr |= SSI_STCR_TFDIR | SSI_STCR_TXDIR;
-               srcr |= SSI_SRCR_RFDIR | SSI_SRCR_RXDIR;
-               break;
-       case SND_SOC_DAIFMT_CBM_CFS:
-               stcr |= SSI_STCR_TFDIR;
-               srcr |= SSI_SRCR_RFDIR;
-               break;
-       case SND_SOC_DAIFMT_CBS_CFM:
-               stcr |= SSI_STCR_TXDIR;
-               srcr |= SSI_SRCR_RXDIR;
-               break;
-       }
-
-       if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
-               SSI1_STCR = stcr;
-               SSI1_SRCR = srcr;
-               SSI1_SCR = scr;
-       } else {
-               SSI2_STCR = stcr;
-               SSI2_SRCR = srcr;
-               SSI2_SCR = scr;
-       }
-
-       return 0;
-}
-
-static int imx_ssi_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;
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               /* set up TX DMA params */
-               switch (cpu_dai->id) {
-               case IMX_DAI_SSI0:
-                       cpu_dai->dma_data = &imx_ssi1_pcm_stereo_out0;
-                       break;
-               case IMX_DAI_SSI1:
-                       cpu_dai->dma_data = &imx_ssi1_pcm_stereo_out1;
-                       break;
-               case IMX_DAI_SSI2:
-                       cpu_dai->dma_data = &imx_ssi2_pcm_stereo_out0;
-                       break;
-               case IMX_DAI_SSI3:
-                       cpu_dai->dma_data = &imx_ssi2_pcm_stereo_out1;
-               }
-               pr_debug("%s: (playback)\n", __func__);
-       } else {
-               /* set up RX DMA params */
-               switch (cpu_dai->id) {
-               case IMX_DAI_SSI0:
-                       cpu_dai->dma_data = &imx_ssi1_pcm_stereo_in0;
-                       break;
-               case IMX_DAI_SSI1:
-                       cpu_dai->dma_data = &imx_ssi1_pcm_stereo_in1;
-                       break;
-               case IMX_DAI_SSI2:
-                       cpu_dai->dma_data = &imx_ssi2_pcm_stereo_in0;
-                       break;
-               case IMX_DAI_SSI3:
-                       cpu_dai->dma_data = &imx_ssi2_pcm_stereo_in1;
-               }
-               pr_debug("%s: (capture)\n", __func__);
-       }
-
-       /*
-        * we cant really change any SSI values after SSI is enabled
-        * need to fix in software for max flexibility - lrg
-        */
-       if (cpu_dai->active) {
-               printk(KERN_WARNING "Warning ssi already enabled\n");
-               return 0;
-       }
-
-       /* reset the SSI port - Sect 45.4.4 */
-       if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
-
-               if (!ssi_clk0)
-                       return -EINVAL;
-
-               if (ssi_active[SSI1_PORT]++) {
-                       pr_debug("%s: exit before reset\n", __func__);
-                       return 0;
-               }
-
-               /* SSI1 Reset */
-               SSI1_SCR = 0;
-
-               SSI1_SFCSR = SSI_SFCSR_RFWM1(RXFIFO_WATERMARK) |
-                       SSI_SFCSR_RFWM0(RXFIFO_WATERMARK) |
-                       SSI_SFCSR_TFWM1(TXFIFO_WATERMARK) |
-                       SSI_SFCSR_TFWM0(TXFIFO_WATERMARK);
-       } else {
-
-               if (!ssi_clk1)
-                       return -EINVAL;
-
-               if (ssi_active[SSI2_PORT]++) {
-                       pr_debug("%s: exit before reset\n", __func__);
-                       return 0;
-               }
-
-               /* SSI2 Reset */
-               SSI2_SCR = 0;
-
-               SSI2_SFCSR = SSI_SFCSR_RFWM1(RXFIFO_WATERMARK) |
-                       SSI_SFCSR_RFWM0(RXFIFO_WATERMARK) |
-                       SSI_SFCSR_TFWM1(TXFIFO_WATERMARK) |
-                       SSI_SFCSR_TFWM0(TXFIFO_WATERMARK);
-       }
-
-       return 0;
-}
-
-int imx_ssi_hw_tx_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;
-       u32 stccr, stcr, sier;
-
-       pr_debug("%s\n", __func__);
-
-       if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
-               stccr = SSI1_STCCR & ~SSI_STCCR_WL_MASK;
-               stcr = SSI1_STCR;
-               sier = SSI1_SIER;
-       } else {
-               stccr = SSI2_STCCR & ~SSI_STCCR_WL_MASK;
-               stcr = SSI2_STCR;
-               sier = SSI2_SIER;
-       }
-
-       /* DAI data (word) size */
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
-               stccr |= SSI_STCCR_WL(16);
-               break;
-       case SNDRV_PCM_FORMAT_S20_3LE:
-               stccr |= SSI_STCCR_WL(20);
-               break;
-       case SNDRV_PCM_FORMAT_S24_LE:
-               stccr |= SSI_STCCR_WL(24);
-               break;
-       }
-
-       /* enable interrupts */
-       if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2)
-               stcr |= SSI_STCR_TFEN0;
-       else
-               stcr |= SSI_STCR_TFEN1;
-       sier |= SSI_SIER_TDMAE;
-
-       if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
-               SSI1_STCR = stcr;
-               SSI1_STCCR = stccr;
-               SSI1_SIER = sier;
-       } else {
-               SSI2_STCR = stcr;
-               SSI2_STCCR = stccr;
-               SSI2_SIER = sier;
-       }
-
-       return 0;
-}
-
-int imx_ssi_hw_rx_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;
-       u32 srccr, srcr, sier;
-
-       pr_debug("%s\n", __func__);
-
-       if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
-               srccr = SSI1_SRCCR & ~SSI_SRCCR_WL_MASK;
-               srcr = SSI1_SRCR;
-               sier = SSI1_SIER;
-       } else {
-               srccr = SSI2_SRCCR & ~SSI_SRCCR_WL_MASK;
-               srcr = SSI2_SRCR;
-               sier = SSI2_SIER;
-       }
-
-       /* DAI data (word) size */
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
-               srccr |= SSI_SRCCR_WL(16);
-               break;
-       case SNDRV_PCM_FORMAT_S20_3LE:
-               srccr |= SSI_SRCCR_WL(20);
-               break;
-       case SNDRV_PCM_FORMAT_S24_LE:
-               srccr |= SSI_SRCCR_WL(24);
-               break;
-       }
-
-       /* enable interrupts */
-       if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2)
-               srcr |= SSI_SRCR_RFEN0;
-       else
-               srcr |= SSI_SRCR_RFEN1;
-       sier |= SSI_SIER_RDMAE;
-
-       if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
-               SSI1_SRCR = srcr;
-               SSI1_SRCCR = srccr;
-               SSI1_SIER = sier;
-       } else {
-               SSI2_SRCR = srcr;
-               SSI2_SRCCR = srccr;
-               SSI2_SIER = sier;
-       }
-
-       return 0;
-}
-
-/*
- * Should only be called when port is inactive (i.e. SSIEN = 0),
- * although can be called multiple times by upper layers.
- */
-int imx_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 snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-
-       int ret;
-
-       /* cant change any parameters when SSI is running */
-       if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
-               if (SSI1_SCR & SSI_SCR_SSIEN) {
-                       printk(KERN_WARNING "Warning ssi already enabled\n");
-                       return 0;
-               }
-       } else {
-               if (SSI2_SCR & SSI_SCR_SSIEN) {
-                       printk(KERN_WARNING "Warning ssi already enabled\n");
-                       return 0;
-               }
-       }
-
-       /*
-        * Configure both tx and rx params with the same settings. This is
-        * really a harware restriction because SSI must be disabled until
-        * we can change those values. If there is an active audio stream in
-        * one direction, enabling the other direction with different
-        * settings would mean disturbing the running one.
-        */
-       ret = imx_ssi_hw_tx_params(substream, params);
-       if (ret < 0)
-               return ret;
-       return imx_ssi_hw_rx_params(substream, params);
-}
-
-int imx_ssi_prepare(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 ret;
-
-       pr_debug("%s\n", __func__);
-
-       /* Enable clks here to follow SSI recommended init sequence */
-       if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
-               ret = clk_enable(ssi_clk0);
-               if (ret < 0)
-                       printk(KERN_ERR "Unable to enable ssi_clk0\n");
-       } else {
-               ret = clk_enable(ssi_clk1);
-               if (ret < 0)
-                       printk(KERN_ERR "Unable to enable ssi_clk1\n");
-       }
-
-       return 0;
-}
-
-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;
-       u32 scr;
-
-       if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2)
-               scr = SSI1_SCR;
-       else
-               scr = SSI2_SCR;
-
-       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)
-                       scr |= SSI_SCR_TE | SSI_SCR_SSIEN;
-               else
-                       scr |= SSI_SCR_RE | SSI_SCR_SSIEN;
-               break;
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       scr &= ~SSI_SCR_TE;
-               else
-                       scr &= ~SSI_SCR_RE;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2)
-               SSI1_SCR = scr;
-       else
-               SSI2_SCR = scr;
-
-       return 0;
-}
-
-static void imx_ssi_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;
-
-       /* shutdown SSI if neither Tx or Rx is active */
-       if (!cpu_dai->active) {
-
-               if (cpu_dai->id == IMX_DAI_SSI0 ||
-                       cpu_dai->id == IMX_DAI_SSI2) {
-
-                       if (--ssi_active[SSI1_PORT] > 1)
-                               return;
-
-                       SSI1_SCR = 0;
-                       clk_disable(ssi_clk0);
-               } else {
-                       if (--ssi_active[SSI2_PORT])
-                               return;
-                       SSI2_SCR = 0;
-                       clk_disable(ssi_clk1);
-               }
-       }
-}
-
-#ifdef CONFIG_PM
-static int imx_ssi_suspend(struct platform_device *dev,
-       struct snd_soc_dai *dai)
-{
-       return 0;
-}
-
-static int imx_ssi_resume(struct platform_device *pdev,
-       struct snd_soc_dai *dai)
-{
-       return 0;
-}
-
-#else
-#define imx_ssi_suspend        NULL
-#define imx_ssi_resume NULL
-#endif
-
-#define IMX_SSI_RATES \
-       (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | \
-       SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
-       SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
-       SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \
-       SNDRV_PCM_RATE_96000)
-
-#define IMX_SSI_BITS \
-       (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
-       SNDRV_PCM_FMTBIT_S24_LE)
-
-static struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = {
-       .startup = imx_ssi_startup,
-       .shutdown = imx_ssi_shutdown,
-       .trigger = imx_ssi_trigger,
-       .prepare = imx_ssi_prepare,
-       .hw_params = imx_ssi_hw_params,
-       .set_sysclk = imx_ssi_set_dai_sysclk,
-       .set_clkdiv = imx_ssi_set_dai_clkdiv,
-       .set_fmt = imx_ssi_set_dai_fmt,
-       .set_tdm_slot = imx_ssi_set_dai_tdm_slot,
-};
-
-struct snd_soc_dai imx_ssi_pcm_dai[] = {
-{
-       .name = "imx-i2s-1-0",
-       .id = IMX_DAI_SSI0,
-       .suspend = imx_ssi_suspend,
-       .resume = imx_ssi_resume,
-       .playback = {
-               .channels_min = 1,
-               .channels_max = 2,
-               .formats = IMX_SSI_BITS,
-               .rates = IMX_SSI_RATES,},
-       .capture = {
-               .channels_min = 1,
-               .channels_max = 2,
-               .formats = IMX_SSI_BITS,
-               .rates = IMX_SSI_RATES,},
-       .ops = &imx_ssi_pcm_dai_ops,
-},
-{
-       .name = "imx-i2s-2-0",
-       .id = IMX_DAI_SSI1,
-       .playback = {
-               .channels_min = 1,
-               .channels_max = 2,
-               .formats = IMX_SSI_BITS,
-               .rates = IMX_SSI_RATES,},
-       .capture = {
-               .channels_min = 1,
-               .channels_max = 2,
-               .formats = IMX_SSI_BITS,
-               .rates = IMX_SSI_RATES,},
-       .ops = &imx_ssi_pcm_dai_ops,
-},
-{
-       .name = "imx-i2s-1-1",
-       .id = IMX_DAI_SSI2,
-       .suspend = imx_ssi_suspend,
-       .resume = imx_ssi_resume,
-       .playback = {
-               .channels_min = 1,
-               .channels_max = 2,
-               .formats = IMX_SSI_BITS,
-               .rates = IMX_SSI_RATES,},
-       .capture = {
-               .channels_min = 1,
-               .channels_max = 2,
-               .formats = IMX_SSI_BITS,
-               .rates = IMX_SSI_RATES,},
-       .ops = &imx_ssi_pcm_dai_ops,
-},
-{
-       .name = "imx-i2s-2-1",
-       .id = IMX_DAI_SSI3,
-       .playback = {
-               .channels_min = 1,
-               .channels_max = 2,
-               .formats = IMX_SSI_BITS,
-               .rates = IMX_SSI_RATES,},
-       .capture = {
-               .channels_min = 1,
-               .channels_max = 2,
-               .formats = IMX_SSI_BITS,
-               .rates = IMX_SSI_RATES,},
-       .ops = &imx_ssi_pcm_dai_ops,
-},
-};
-EXPORT_SYMBOL_GPL(imx_ssi_pcm_dai);
-
-static int __init imx_ssi_init(void)
-{
-       return snd_soc_register_dais(imx_ssi_pcm_dai,
-                               ARRAY_SIZE(imx_ssi_pcm_dai));
-}
-
-static void __exit imx_ssi_exit(void)
-{
-       snd_soc_unregister_dais(imx_ssi_pcm_dai,
-                               ARRAY_SIZE(imx_ssi_pcm_dai));
-}
-
-module_init(imx_ssi_init);
-module_exit(imx_ssi_exit);
-MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com");
-MODULE_DESCRIPTION("i.MX ASoC I2S driver");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/imx/mxc-ssi.h b/sound/soc/imx/mxc-ssi.h
deleted file mode 100644 (file)
index 12bbdc9..0000000
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _IMX_SSI_H
-#define _IMX_SSI_H
-
-#include <mach/hardware.h>
-
-/* SSI regs definition - MOVE to /arch/arm/plat-mxc/include/mach/ when stable */
-#define SSI1_IO_BASE_ADDR      IO_ADDRESS(SSI1_BASE_ADDR)
-#define SSI2_IO_BASE_ADDR      IO_ADDRESS(SSI2_BASE_ADDR)
-
-#define STX0   0x00
-#define STX1   0x04
-#define SRX0   0x08
-#define SRX1   0x0c
-#define SCR    0x10
-#define SISR   0x14
-#define SIER   0x18
-#define STCR   0x1c
-#define SRCR   0x20
-#define STCCR  0x24
-#define SRCCR  0x28
-#define SFCSR  0x2c
-#define STR    0x30
-#define SOR    0x34
-#define SACNT  0x38
-#define SACADD 0x3c
-#define SACDAT 0x40
-#define SATAG  0x44
-#define STMSK  0x48
-#define SRMSK  0x4c
-
-#define SSI1_STX0      (*((volatile u32 *)(SSI1_IO_BASE_ADDR + STX0)))
-#define SSI1_STX1   (*((volatile u32 *)(SSI1_IO_BASE_ADDR + STX1)))
-#define SSI1_SRX0   (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SRX0)))
-#define SSI1_SRX1   (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SRX1)))
-#define SSI1_SCR    (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SCR)))
-#define SSI1_SISR   (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SISR)))
-#define SSI1_SIER   (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SIER)))
-#define SSI1_STCR   (*((volatile u32 *)(SSI1_IO_BASE_ADDR + STCR)))
-#define SSI1_SRCR   (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SRCR)))
-#define SSI1_STCCR  (*((volatile u32 *)(SSI1_IO_BASE_ADDR + STCCR)))
-#define SSI1_SRCCR  (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SRCCR)))
-#define SSI1_SFCSR  (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SFCSR)))
-#define SSI1_STR    (*((volatile u32 *)(SSI1_IO_BASE_ADDR + STR)))
-#define SSI1_SOR    (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SOR)))
-#define SSI1_SACNT  (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SACNT)))
-#define SSI1_SACADD (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SACADD)))
-#define SSI1_SACDAT (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SACDAT)))
-#define SSI1_SATAG  (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SATAG)))
-#define SSI1_STMSK  (*((volatile u32 *)(SSI1_IO_BASE_ADDR + STMSK)))
-#define SSI1_SRMSK  (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SRMSK)))
-
-
-#define SSI2_STX0      (*((volatile u32 *)(SSI2_IO_BASE_ADDR + STX0)))
-#define SSI2_STX1   (*((volatile u32 *)(SSI2_IO_BASE_ADDR + STX1)))
-#define SSI2_SRX0   (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SRX0)))
-#define SSI2_SRX1   (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SRX1)))
-#define SSI2_SCR    (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SCR)))
-#define SSI2_SISR   (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SISR)))
-#define SSI2_SIER   (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SIER)))
-#define SSI2_STCR   (*((volatile u32 *)(SSI2_IO_BASE_ADDR + STCR)))
-#define SSI2_SRCR   (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SRCR)))
-#define SSI2_STCCR  (*((volatile u32 *)(SSI2_IO_BASE_ADDR + STCCR)))
-#define SSI2_SRCCR  (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SRCCR)))
-#define SSI2_SFCSR  (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SFCSR)))
-#define SSI2_STR    (*((volatile u32 *)(SSI2_IO_BASE_ADDR + STR)))
-#define SSI2_SOR    (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SOR)))
-#define SSI2_SACNT  (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SACNT)))
-#define SSI2_SACADD (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SACADD)))
-#define SSI2_SACDAT (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SACDAT)))
-#define SSI2_SATAG  (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SATAG)))
-#define SSI2_STMSK  (*((volatile u32 *)(SSI2_IO_BASE_ADDR + STMSK)))
-#define SSI2_SRMSK  (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SRMSK)))
-
-#define SSI_SCR_CLK_IST        (1 << 9)
-#define SSI_SCR_TCH_EN         (1 << 8)
-#define SSI_SCR_SYS_CLK_EN     (1 << 7)
-#define SSI_SCR_I2S_MODE_NORM  (0 << 5)
-#define SSI_SCR_I2S_MODE_MSTR  (1 << 5)
-#define SSI_SCR_I2S_MODE_SLAVE (2 << 5)
-#define SSI_SCR_SYN            (1 << 4)
-#define SSI_SCR_NET            (1 << 3)
-#define SSI_SCR_RE             (1 << 2)
-#define SSI_SCR_TE             (1 << 1)
-#define SSI_SCR_SSIEN          (1 << 0)
-
-#define SSI_SISR_CMDAU         (1 << 18)
-#define SSI_SISR_CMDDU         (1 << 17)
-#define SSI_SISR_RXT           (1 << 16)
-#define SSI_SISR_RDR1          (1 << 15)
-#define SSI_SISR_RDR0          (1 << 14)
-#define SSI_SISR_TDE1          (1 << 13)
-#define SSI_SISR_TDE0          (1 << 12)
-#define SSI_SISR_ROE1          (1 << 11)
-#define SSI_SISR_ROE0          (1 << 10)
-#define SSI_SISR_TUE1          (1 << 9)
-#define SSI_SISR_TUE0          (1 << 8)
-#define SSI_SISR_TFS           (1 << 7)
-#define SSI_SISR_RFS           (1 << 6)
-#define SSI_SISR_TLS           (1 << 5)
-#define SSI_SISR_RLS           (1 << 4)
-#define SSI_SISR_RFF1          (1 << 3)
-#define SSI_SISR_RFF0          (1 << 2)
-#define SSI_SISR_TFE1          (1 << 1)
-#define SSI_SISR_TFE0          (1 << 0)
-
-#define SSI_SIER_RDMAE         (1 << 22)
-#define SSI_SIER_RIE           (1 << 21)
-#define SSI_SIER_TDMAE         (1 << 20)
-#define SSI_SIER_TIE           (1 << 19)
-#define SSI_SIER_CMDAU_EN      (1 << 18)
-#define SSI_SIER_CMDDU_EN      (1 << 17)
-#define SSI_SIER_RXT_EN        (1 << 16)
-#define SSI_SIER_RDR1_EN       (1 << 15)
-#define SSI_SIER_RDR0_EN       (1 << 14)
-#define SSI_SIER_TDE1_EN       (1 << 13)
-#define SSI_SIER_TDE0_EN       (1 << 12)
-#define SSI_SIER_ROE1_EN       (1 << 11)
-#define SSI_SIER_ROE0_EN       (1 << 10)
-#define SSI_SIER_TUE1_EN       (1 << 9)
-#define SSI_SIER_TUE0_EN       (1 << 8)
-#define SSI_SIER_TFS_EN        (1 << 7)
-#define SSI_SIER_RFS_EN        (1 << 6)
-#define SSI_SIER_TLS_EN        (1 << 5)
-#define SSI_SIER_RLS_EN        (1 << 4)
-#define SSI_SIER_RFF1_EN       (1 << 3)
-#define SSI_SIER_RFF0_EN       (1 << 2)
-#define SSI_SIER_TFE1_EN       (1 << 1)
-#define SSI_SIER_TFE0_EN       (1 << 0)
-
-#define SSI_STCR_TXBIT0        (1 << 9)
-#define SSI_STCR_TFEN1         (1 << 8)
-#define SSI_STCR_TFEN0         (1 << 7)
-#define SSI_STCR_TFDIR         (1 << 6)
-#define SSI_STCR_TXDIR         (1 << 5)
-#define SSI_STCR_TSHFD         (1 << 4)
-#define SSI_STCR_TSCKP         (1 << 3)
-#define SSI_STCR_TFSI          (1 << 2)
-#define SSI_STCR_TFSL          (1 << 1)
-#define SSI_STCR_TEFS          (1 << 0)
-
-#define SSI_SRCR_RXBIT0        (1 << 9)
-#define SSI_SRCR_RFEN1         (1 << 8)
-#define SSI_SRCR_RFEN0         (1 << 7)
-#define SSI_SRCR_RFDIR         (1 << 6)
-#define SSI_SRCR_RXDIR         (1 << 5)
-#define SSI_SRCR_RSHFD         (1 << 4)
-#define SSI_SRCR_RSCKP         (1 << 3)
-#define SSI_SRCR_RFSI          (1 << 2)
-#define SSI_SRCR_RFSL          (1 << 1)
-#define SSI_SRCR_REFS          (1 << 0)
-
-#define SSI_STCCR_DIV2         (1 << 18)
-#define SSI_STCCR_PSR          (1 << 15)
-#define SSI_STCCR_WL(x)        ((((x) - 2) >> 1) << 13)
-#define SSI_STCCR_DC(x)        (((x) & 0x1f) << 8)
-#define SSI_STCCR_PM(x)        (((x) & 0xff) << 0)
-#define SSI_STCCR_WL_MASK        (0xf << 13)
-#define SSI_STCCR_DC_MASK        (0x1f << 8)
-#define SSI_STCCR_PM_MASK        (0xff << 0)
-
-#define SSI_SRCCR_DIV2         (1 << 18)
-#define SSI_SRCCR_PSR          (1 << 15)
-#define SSI_SRCCR_WL(x)        ((((x) - 2) >> 1) << 13)
-#define SSI_SRCCR_DC(x)        (((x) & 0x1f) << 8)
-#define SSI_SRCCR_PM(x)        (((x) & 0xff) << 0)
-#define SSI_SRCCR_WL_MASK        (0xf << 13)
-#define SSI_SRCCR_DC_MASK        (0x1f << 8)
-#define SSI_SRCCR_PM_MASK        (0xff << 0)
-
-
-#define SSI_SFCSR_RFCNT1(x)   (((x) & 0xf) << 28)
-#define SSI_SFCSR_TFCNT1(x)   (((x) & 0xf) << 24)
-#define SSI_SFCSR_RFWM1(x)    (((x) & 0xf) << 20)
-#define SSI_SFCSR_TFWM1(x)    (((x) & 0xf) << 16)
-#define SSI_SFCSR_RFCNT0(x)   (((x) & 0xf) << 12)
-#define SSI_SFCSR_TFCNT0(x)   (((x) & 0xf) <<  8)
-#define SSI_SFCSR_RFWM0(x)    (((x) & 0xf) <<  4)
-#define SSI_SFCSR_TFWM0(x)    (((x) & 0xf) <<  0)
-
-#define SSI_STR_TEST          (1 << 15)
-#define SSI_STR_RCK2TCK       (1 << 14)
-#define SSI_STR_RFS2TFS       (1 << 13)
-#define SSI_STR_RXSTATE(x)    (((x) & 0xf) << 8)
-#define SSI_STR_TXD2RXD       (1 <<  7)
-#define SSI_STR_TCK2RCK       (1 <<  6)
-#define SSI_STR_TFS2RFS       (1 <<  5)
-#define SSI_STR_TXSTATE(x)    (((x) & 0xf) << 0)
-
-#define SSI_SOR_CLKOFF        (1 << 6)
-#define SSI_SOR_RX_CLR        (1 << 5)
-#define SSI_SOR_TX_CLR        (1 << 4)
-#define SSI_SOR_INIT          (1 << 3)
-#define SSI_SOR_WAIT(x)       (((x) & 0x3) << 1)
-#define SSI_SOR_SYNRST        (1 << 0)
-
-#define SSI_SACNT_FRDIV(x)    (((x) & 0x3f) << 5)
-#define SSI_SACNT_WR          (x << 4)
-#define SSI_SACNT_RD          (x << 3)
-#define SSI_SACNT_TIF         (x << 2)
-#define SSI_SACNT_FV          (x << 1)
-#define SSI_SACNT_AC97EN      (x << 0)
-
-/* Watermarks for FIFO's */
-#define TXFIFO_WATERMARK                               0x4
-#define RXFIFO_WATERMARK                               0x4
-
-/* i.MX DAI SSP ID's */
-#define IMX_DAI_SSI0                   0 /* SSI1 FIFO 0 */
-#define IMX_DAI_SSI1                   1 /* SSI1 FIFO 1 */
-#define IMX_DAI_SSI2                   2 /* SSI2 FIFO 0 */
-#define IMX_DAI_SSI3                   3 /* SSI2 FIFO 1 */
-
-/* SSI clock sources */
-#define IMX_SSP_SYS_CLK                0
-
-/* SSI audio dividers */
-#define IMX_SSI_TX_DIV_2                       0
-#define IMX_SSI_TX_DIV_PSR                     1
-#define IMX_SSI_TX_DIV_PM                      2
-#define IMX_SSI_RX_DIV_2                       3
-#define IMX_SSI_RX_DIV_PSR                     4
-#define IMX_SSI_RX_DIV_PM                      5
-
-
-/* SSI Div 2 */
-#define IMX_SSI_DIV_2_OFF              (~SSI_STCCR_DIV2)
-#define IMX_SSI_DIV_2_ON               SSI_STCCR_DIV2
-
-extern struct snd_soc_dai imx_ssi_pcm_dai[4];
-extern int get_ssi_clk(int ssi, struct device *dev);
-extern void put_ssi_clk(int ssi);
-#endif
diff --git a/sound/soc/imx/phycore-ac97.c b/sound/soc/imx/phycore-ac97.c
new file mode 100644 (file)
index 0000000..a8307d5
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * phycore-ac97.c  --  SoC audio for imx_phycore in AC97 mode
+ *
+ * Copyright 2009 Sascha Hauer, Pengutronix <s.hauer@pengutronix.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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <asm/mach-types.h>
+
+#include "../codecs/wm9712.h"
+#include "imx-ssi.h"
+
+static struct snd_soc_card imx_phycore;
+
+static struct snd_soc_ops imx_phycore_hifi_ops = {
+};
+
+static struct snd_soc_dai_link imx_phycore_dai_ac97[] = {
+       {
+               .name           = "HiFi",
+               .stream_name    = "HiFi",
+               .codec_dai      = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+               .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)
+{
+       int ret;
+
+       if (!machine_is_pcm043() && !machine_is_pca100())
+               /* return happy. We might run on a totally different machine */
+               return 0;
+
+       imx_phycore_snd_device = platform_device_alloc("soc-audio", -1);
+       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_snd_devdata);
+       imx_phycore_snd_devdata.dev = &imx_phycore_snd_device->dev;
+       ret = platform_device_add(imx_phycore_snd_device);
+
+       if (ret) {
+               printk(KERN_ERR "ASoC: Platform device allocation failed\n");
+               platform_device_put(imx_phycore_snd_device);
+       }
+
+       return ret;
+}
+
+static void __exit imx_phycore_exit(void)
+{
+       platform_device_unregister(imx_phycore_snd_device);
+}
+
+late_initcall(imx_phycore_init);
+module_exit(imx_phycore_exit);
+
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_DESCRIPTION("PhyCORE ALSA SoC driver");
+MODULE_LICENSE("GPL");
index 61952aa6cd5ac34a8a14e0324ccf2d036872eae8..f11963c218730ae2545df1af0c7b2eeba017216e 100644 (file)
@@ -6,6 +6,9 @@ config SND_OMAP_SOC_MCBSP
        tristate
        select OMAP_MCBSP
 
+config SND_OMAP_SOC_MCPDM
+       tristate
+
 config SND_OMAP_SOC_N810
        tristate "SoC Audio support for Nokia N810"
        depends on SND_OMAP_SOC && MACH_NOKIA_N810 && I2C
@@ -94,12 +97,14 @@ config SND_OMAP_SOC_OMAP3_PANDORA
          Say Y if you want to add support for SoC audio on the OMAP3 Pandora.
 
 config SND_OMAP_SOC_OMAP3_BEAGLE
-       tristate "SoC Audio support for OMAP3 Beagle"
-       depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3_BEAGLE
+       tristate "SoC Audio support for OMAP3 Beagle and Devkit8000"
+       depends on TWL4030_CORE && SND_OMAP_SOC
+       depends on (MACH_OMAP3_BEAGLE || MACH_DEVKIT8000)
        select SND_OMAP_SOC_MCBSP
        select SND_SOC_TWL4030
        help
-         Say Y if you want to add support for SoC audio on the Beagleboard.
+         Say Y if you want to add support for SoC audio on the Beagleboard or
+         the clone Devkit8000.
 
 config SND_OMAP_SOC_ZOOM2
        tristate "SoC Audio support for Zoom2"
index 19283e5edfbf8b4fbcb9af817408bb954f23bd39..0bc00ca14b375d9b4d1bdfb8b2ddf0d03533abc4 100644 (file)
@@ -1,9 +1,11 @@
 # OMAP Platform Support
 snd-soc-omap-objs := omap-pcm.o
 snd-soc-omap-mcbsp-objs := omap-mcbsp.o
+snd-soc-omap-mcpdm-objs := omap-mcpdm.o mcpdm.o
 
 obj-$(CONFIG_SND_OMAP_SOC) += snd-soc-omap.o
 obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o
+obj-$(CONFIG_SND_OMAP_SOC_MCPDM) += snd-soc-omap-mcpdm.o
 
 # OMAP Machine Support
 snd-soc-n810-objs := n810.o
diff --git a/sound/soc/omap/mcpdm.c b/sound/soc/omap/mcpdm.c
new file mode 100644 (file)
index 0000000..ad8df6c
--- /dev/null
@@ -0,0 +1,484 @@
+/*
+ * mcpdm.c  --  McPDM interface driver
+ *
+ * Author: Jorge Eduardo Candelaria <x0107209@ti.com>
+ * Copyright (C) 2009 - Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include "mcpdm.h"
+
+static struct omap_mcpdm *mcpdm;
+
+static inline void omap_mcpdm_write(u16 reg, u32 val)
+{
+       __raw_writel(val, mcpdm->io_base + reg);
+}
+
+static inline int omap_mcpdm_read(u16 reg)
+{
+       return __raw_readl(mcpdm->io_base + reg);
+}
+
+static void omap_mcpdm_reg_dump(void)
+{
+       dev_dbg(mcpdm->dev, "***********************\n");
+       dev_dbg(mcpdm->dev, "IRQSTATUS_RAW:  0x%04x\n",
+                       omap_mcpdm_read(MCPDM_IRQSTATUS_RAW));
+       dev_dbg(mcpdm->dev, "IRQSTATUS:  0x%04x\n",
+                       omap_mcpdm_read(MCPDM_IRQSTATUS));
+       dev_dbg(mcpdm->dev, "IRQENABLE_SET:  0x%04x\n",
+                       omap_mcpdm_read(MCPDM_IRQENABLE_SET));
+       dev_dbg(mcpdm->dev, "IRQENABLE_CLR:  0x%04x\n",
+                       omap_mcpdm_read(MCPDM_IRQENABLE_CLR));
+       dev_dbg(mcpdm->dev, "IRQWAKE_EN: 0x%04x\n",
+                       omap_mcpdm_read(MCPDM_IRQWAKE_EN));
+       dev_dbg(mcpdm->dev, "DMAENABLE_SET: 0x%04x\n",
+                       omap_mcpdm_read(MCPDM_DMAENABLE_SET));
+       dev_dbg(mcpdm->dev, "DMAENABLE_CLR:  0x%04x\n",
+                       omap_mcpdm_read(MCPDM_DMAENABLE_CLR));
+       dev_dbg(mcpdm->dev, "DMAWAKEEN:  0x%04x\n",
+                       omap_mcpdm_read(MCPDM_DMAWAKEEN));
+       dev_dbg(mcpdm->dev, "CTRL:  0x%04x\n",
+                       omap_mcpdm_read(MCPDM_CTRL));
+       dev_dbg(mcpdm->dev, "DN_DATA:  0x%04x\n",
+                       omap_mcpdm_read(MCPDM_DN_DATA));
+       dev_dbg(mcpdm->dev, "UP_DATA: 0x%04x\n",
+                       omap_mcpdm_read(MCPDM_UP_DATA));
+       dev_dbg(mcpdm->dev, "FIFO_CTRL_DN: 0x%04x\n",
+                       omap_mcpdm_read(MCPDM_FIFO_CTRL_DN));
+       dev_dbg(mcpdm->dev, "FIFO_CTRL_UP:  0x%04x\n",
+                       omap_mcpdm_read(MCPDM_FIFO_CTRL_UP));
+       dev_dbg(mcpdm->dev, "DN_OFFSET:  0x%04x\n",
+                       omap_mcpdm_read(MCPDM_DN_OFFSET));
+       dev_dbg(mcpdm->dev, "***********************\n");
+}
+
+/*
+ * Takes the McPDM module in and out of reset state.
+ * Uplink and downlink can be reset individually.
+ */
+static void omap_mcpdm_reset_capture(int reset)
+{
+       int ctrl = omap_mcpdm_read(MCPDM_CTRL);
+
+       if (reset)
+               ctrl |= SW_UP_RST;
+       else
+               ctrl &= ~SW_UP_RST;
+
+       omap_mcpdm_write(MCPDM_CTRL, ctrl);
+}
+
+static void omap_mcpdm_reset_playback(int reset)
+{
+       int ctrl = omap_mcpdm_read(MCPDM_CTRL);
+
+       if (reset)
+               ctrl |= SW_DN_RST;
+       else
+               ctrl &= ~SW_DN_RST;
+
+       omap_mcpdm_write(MCPDM_CTRL, ctrl);
+}
+
+/*
+ * Enables the transfer through the PDM interface to/from the Phoenix
+ * codec by enabling the corresponding UP or DN channels.
+ */
+void omap_mcpdm_start(int stream)
+{
+       int ctrl = omap_mcpdm_read(MCPDM_CTRL);
+
+       if (stream)
+               ctrl |= mcpdm->up_channels;
+       else
+               ctrl |= mcpdm->dn_channels;
+
+       omap_mcpdm_write(MCPDM_CTRL, ctrl);
+}
+
+/*
+ * Disables the transfer through the PDM interface to/from the Phoenix
+ * codec by disabling the corresponding UP or DN channels.
+ */
+void omap_mcpdm_stop(int stream)
+{
+       int ctrl = omap_mcpdm_read(MCPDM_CTRL);
+
+       if (stream)
+               ctrl &= ~mcpdm->up_channels;
+       else
+               ctrl &= ~mcpdm->dn_channels;
+
+       omap_mcpdm_write(MCPDM_CTRL, ctrl);
+}
+
+/*
+ * Configures McPDM uplink for audio recording.
+ * This function should be called before omap_mcpdm_start.
+ */
+int omap_mcpdm_capture_open(struct omap_mcpdm_link *uplink)
+{
+       int irq_mask = 0;
+       int ctrl;
+
+       if (!uplink)
+               return -EINVAL;
+
+       mcpdm->uplink = uplink;
+
+       /* Enable irq request generation */
+       irq_mask |= uplink->irq_mask & MCPDM_UPLINK_IRQ_MASK;
+       omap_mcpdm_write(MCPDM_IRQENABLE_SET, irq_mask);
+
+       /* Configure uplink threshold */
+       if (uplink->threshold > UP_THRES_MAX)
+               uplink->threshold = UP_THRES_MAX;
+
+       omap_mcpdm_write(MCPDM_FIFO_CTRL_UP, uplink->threshold);
+
+       /* Configure DMA controller */
+       omap_mcpdm_write(MCPDM_DMAENABLE_SET, DMA_UP_ENABLE);
+
+       /* Set pdm out format */
+       ctrl = omap_mcpdm_read(MCPDM_CTRL);
+       ctrl &= ~PDMOUTFORMAT;
+       ctrl |= uplink->format & PDMOUTFORMAT;
+
+       /* Uplink channels */
+       mcpdm->up_channels = uplink->channels & (PDM_UP_MASK | PDM_STATUS_MASK);
+
+       omap_mcpdm_write(MCPDM_CTRL, ctrl);
+
+       return 0;
+}
+
+/*
+ * Configures McPDM downlink for audio playback.
+ * This function should be called before omap_mcpdm_start.
+ */
+int omap_mcpdm_playback_open(struct omap_mcpdm_link *downlink)
+{
+       int irq_mask = 0;
+       int ctrl;
+
+       if (!downlink)
+               return -EINVAL;
+
+       mcpdm->downlink = downlink;
+
+       /* Enable irq request generation */
+       irq_mask |= downlink->irq_mask & MCPDM_DOWNLINK_IRQ_MASK;
+       omap_mcpdm_write(MCPDM_IRQENABLE_SET, irq_mask);
+
+       /* Configure uplink threshold */
+       if (downlink->threshold > DN_THRES_MAX)
+               downlink->threshold = DN_THRES_MAX;
+
+       omap_mcpdm_write(MCPDM_FIFO_CTRL_DN, downlink->threshold);
+
+       /* Enable DMA request generation */
+       omap_mcpdm_write(MCPDM_DMAENABLE_SET, DMA_DN_ENABLE);
+
+       /* Set pdm out format */
+       ctrl = omap_mcpdm_read(MCPDM_CTRL);
+       ctrl &= ~PDMOUTFORMAT;
+       ctrl |= downlink->format & PDMOUTFORMAT;
+
+       /* Downlink channels */
+       mcpdm->dn_channels = downlink->channels & (PDM_DN_MASK | PDM_CMD_MASK);
+
+       omap_mcpdm_write(MCPDM_CTRL, ctrl);
+
+       return 0;
+}
+
+/*
+ * Cleans McPDM uplink configuration.
+ * This function should be called when the stream is closed.
+ */
+int omap_mcpdm_capture_close(struct omap_mcpdm_link *uplink)
+{
+       int irq_mask = 0;
+
+       if (!uplink)
+               return -EINVAL;
+
+       /* Disable irq request generation */
+       irq_mask |= uplink->irq_mask & MCPDM_UPLINK_IRQ_MASK;
+       omap_mcpdm_write(MCPDM_IRQENABLE_CLR, irq_mask);
+
+       /* Disable DMA request generation */
+       omap_mcpdm_write(MCPDM_DMAENABLE_CLR, DMA_UP_ENABLE);
+
+       /* Clear Downlink channels */
+       mcpdm->up_channels = 0;
+
+       mcpdm->uplink = NULL;
+
+       return 0;
+}
+
+/*
+ * Cleans McPDM downlink configuration.
+ * This function should be called when the stream is closed.
+ */
+int omap_mcpdm_playback_close(struct omap_mcpdm_link *downlink)
+{
+       int irq_mask = 0;
+
+       if (!downlink)
+               return -EINVAL;
+
+       /* Disable irq request generation */
+       irq_mask |= downlink->irq_mask & MCPDM_DOWNLINK_IRQ_MASK;
+       omap_mcpdm_write(MCPDM_IRQENABLE_CLR, irq_mask);
+
+       /* Disable DMA request generation */
+       omap_mcpdm_write(MCPDM_DMAENABLE_CLR, DMA_DN_ENABLE);
+
+       /* clear Downlink channels */
+       mcpdm->dn_channels = 0;
+
+       mcpdm->downlink = NULL;
+
+       return 0;
+}
+
+static irqreturn_t omap_mcpdm_irq_handler(int irq, void *dev_id)
+{
+       struct omap_mcpdm *mcpdm_irq = dev_id;
+       int irq_status;
+
+       irq_status = omap_mcpdm_read(MCPDM_IRQSTATUS);
+
+       /* Acknowledge irq event */
+       omap_mcpdm_write(MCPDM_IRQSTATUS, irq_status);
+
+       if (irq & MCPDM_DN_IRQ_FULL) {
+               dev_err(mcpdm_irq->dev, "DN FIFO error %x\n", irq_status);
+               omap_mcpdm_reset_playback(1);
+               omap_mcpdm_playback_open(mcpdm_irq->downlink);
+               omap_mcpdm_reset_playback(0);
+       }
+
+       if (irq & MCPDM_DN_IRQ_EMPTY) {
+               dev_err(mcpdm_irq->dev, "DN FIFO error %x\n", irq_status);
+               omap_mcpdm_reset_playback(1);
+               omap_mcpdm_playback_open(mcpdm_irq->downlink);
+               omap_mcpdm_reset_playback(0);
+       }
+
+       if (irq & MCPDM_DN_IRQ) {
+               dev_dbg(mcpdm_irq->dev, "DN write request\n");
+       }
+
+       if (irq & MCPDM_UP_IRQ_FULL) {
+               dev_err(mcpdm_irq->dev, "UP FIFO error %x\n", irq_status);
+               omap_mcpdm_reset_capture(1);
+               omap_mcpdm_capture_open(mcpdm_irq->uplink);
+               omap_mcpdm_reset_capture(0);
+       }
+
+       if (irq & MCPDM_UP_IRQ_EMPTY) {
+               dev_err(mcpdm_irq->dev, "UP FIFO error %x\n", irq_status);
+               omap_mcpdm_reset_capture(1);
+               omap_mcpdm_capture_open(mcpdm_irq->uplink);
+               omap_mcpdm_reset_capture(0);
+       }
+
+       if (irq & MCPDM_UP_IRQ) {
+               dev_dbg(mcpdm_irq->dev, "UP write request\n");
+       }
+
+       return IRQ_HANDLED;
+}
+
+int omap_mcpdm_request(void)
+{
+       int ret;
+
+       clk_enable(mcpdm->clk);
+
+       spin_lock(&mcpdm->lock);
+
+       if (!mcpdm->free) {
+               dev_err(mcpdm->dev, "McPDM interface is in use\n");
+               spin_unlock(&mcpdm->lock);
+               ret = -EBUSY;
+               goto err;
+       }
+       mcpdm->free = 0;
+
+       spin_unlock(&mcpdm->lock);
+
+       /* Disable lines while request is ongoing */
+       omap_mcpdm_write(MCPDM_CTRL, 0x00);
+
+       ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler,
+                               0, "McPDM", (void *)mcpdm);
+       if (ret) {
+               dev_err(mcpdm->dev, "Request for McPDM IRQ failed\n");
+               goto err;
+       }
+
+       return 0;
+
+err:
+       clk_disable(mcpdm->clk);
+       return ret;
+}
+
+void omap_mcpdm_free(void)
+{
+       spin_lock(&mcpdm->lock);
+       if (mcpdm->free) {
+               dev_err(mcpdm->dev, "McPDM interface is already free\n");
+               spin_unlock(&mcpdm->lock);
+               return;
+       }
+       mcpdm->free = 1;
+       spin_unlock(&mcpdm->lock);
+
+       clk_disable(mcpdm->clk);
+
+       free_irq(mcpdm->irq, (void *)mcpdm);
+}
+
+/* Enable/disable DC offset cancelation for the analog
+ * headset path (PDM channels 1 and 2).
+ */
+int omap_mcpdm_set_offset(int offset1, int offset2)
+{
+       int offset;
+
+       if ((offset1 > DN_OFST_MAX) || (offset2 > DN_OFST_MAX))
+               return -EINVAL;
+
+       offset = (offset1 << DN_OFST_RX1) | (offset2 << DN_OFST_RX2);
+
+       /* offset cancellation for channel 1 */
+       if (offset1)
+               offset |= DN_OFST_RX1_EN;
+       else
+               offset &= ~DN_OFST_RX1_EN;
+
+       /* offset cancellation for channel 2 */
+       if (offset2)
+               offset |= DN_OFST_RX2_EN;
+       else
+               offset &= ~DN_OFST_RX2_EN;
+
+       omap_mcpdm_write(MCPDM_DN_OFFSET, offset);
+
+       return 0;
+}
+
+static int __devinit omap_mcpdm_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       int ret = 0;
+
+       mcpdm = kzalloc(sizeof(struct omap_mcpdm), GFP_KERNEL);
+       if (!mcpdm) {
+               ret = -ENOMEM;
+               goto exit;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "no resource\n");
+               goto err_resource;
+       }
+
+       spin_lock_init(&mcpdm->lock);
+       mcpdm->free = 1;
+       mcpdm->io_base = ioremap(res->start, resource_size(res));
+       if (!mcpdm->io_base) {
+               ret = -ENOMEM;
+               goto err_resource;
+       }
+
+       mcpdm->irq = platform_get_irq(pdev, 0);
+
+       mcpdm->clk = clk_get(&pdev->dev, "pdm_ck");
+       if (IS_ERR(mcpdm->clk)) {
+               ret = PTR_ERR(mcpdm->clk);
+               dev_err(&pdev->dev, "unable to get pdm_ck: %d\n", ret);
+               goto err_clk;
+       }
+
+       mcpdm->dev = &pdev->dev;
+       platform_set_drvdata(pdev, mcpdm);
+
+       return 0;
+
+err_clk:
+       iounmap(mcpdm->io_base);
+err_resource:
+       kfree(mcpdm);
+exit:
+       return ret;
+}
+
+static int __devexit omap_mcpdm_remove(struct platform_device *pdev)
+{
+       struct omap_mcpdm *mcpdm_ptr = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+
+       clk_put(mcpdm_ptr->clk);
+
+       iounmap(mcpdm_ptr->io_base);
+
+       mcpdm_ptr->clk = NULL;
+       mcpdm_ptr->free = 0;
+       mcpdm_ptr->dev = NULL;
+
+       kfree(mcpdm_ptr);
+
+       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);
diff --git a/sound/soc/omap/mcpdm.h b/sound/soc/omap/mcpdm.h
new file mode 100644 (file)
index 0000000..7bb326e
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * mcpdm.h -- Defines for McPDM driver
+ *
+ * Author: Jorge Eduardo Candelaria <x0107209@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
+ *
+ */
+
+/* McPDM registers */
+
+#define MCPDM_REVISION         0x00
+#define MCPDM_SYSCONFIG                0x10
+#define MCPDM_IRQSTATUS_RAW    0x24
+#define MCPDM_IRQSTATUS                0x28
+#define MCPDM_IRQENABLE_SET    0x2C
+#define MCPDM_IRQENABLE_CLR    0x30
+#define MCPDM_IRQWAKE_EN       0x34
+#define MCPDM_DMAENABLE_SET    0x38
+#define MCPDM_DMAENABLE_CLR    0x3C
+#define MCPDM_DMAWAKEEN                0x40
+#define MCPDM_CTRL             0x44
+#define MCPDM_DN_DATA          0x48
+#define MCPDM_UP_DATA          0x4C
+#define MCPDM_FIFO_CTRL_DN     0x50
+#define MCPDM_FIFO_CTRL_UP     0x54
+#define MCPDM_DN_OFFSET                0x58
+
+/*
+ * MCPDM_IRQ bit fields
+ * IRQSTATUS_RAW, IRQSTATUS, IRQENABLE_SET, IRQENABLE_CLR
+ */
+
+#define MCPDM_DN_IRQ                   (1 << 0)
+#define MCPDM_DN_IRQ_EMPTY             (1 << 1)
+#define MCPDM_DN_IRQ_ALMST_EMPTY       (1 << 2)
+#define MCPDM_DN_IRQ_FULL              (1 << 3)
+
+#define MCPDM_UP_IRQ                   (1 << 8)
+#define MCPDM_UP_IRQ_EMPTY             (1 << 9)
+#define MCPDM_UP_IRQ_ALMST_FULL                (1 << 10)
+#define MCPDM_UP_IRQ_FULL              (1 << 11)
+
+#define MCPDM_DOWNLINK_IRQ_MASK                0x00F
+#define MCPDM_UPLINK_IRQ_MASK          0xF00
+
+/*
+ * MCPDM_DMAENABLE bit fields
+ */
+
+#define DMA_DN_ENABLE          0x1
+#define DMA_UP_ENABLE          0x2
+
+/*
+ * MCPDM_CTRL bit fields
+ */
+
+#define PDM_UP1_EN             0x0001
+#define PDM_UP2_EN             0x0002
+#define PDM_UP3_EN             0x0004
+#define PDM_DN1_EN             0x0008
+#define PDM_DN2_EN             0x0010
+#define PDM_DN3_EN             0x0020
+#define PDM_DN4_EN             0x0040
+#define PDM_DN5_EN             0x0080
+#define PDMOUTFORMAT           0x0100
+#define CMD_INT                        0x0200
+#define STATUS_INT             0x0400
+#define SW_UP_RST              0x0800
+#define SW_DN_RST              0x1000
+#define PDM_UP_MASK            0x007
+#define PDM_DN_MASK            0x0F8
+#define PDM_CMD_MASK           0x200
+#define PDM_STATUS_MASK                0x400
+
+
+#define PDMOUTFORMAT_LJUST     (0 << 8)
+#define PDMOUTFORMAT_RJUST     (1 << 8)
+
+/*
+ * MCPDM_FIFO_CTRL bit fields
+ */
+
+#define UP_THRES_MAX           0xF
+#define DN_THRES_MAX           0xF
+
+/*
+ * MCPDM_DN_OFFSET bit fields
+ */
+
+#define DN_OFST_RX1_EN         0x0001
+#define DN_OFST_RX2_EN         0x0100
+
+#define DN_OFST_RX1            1
+#define DN_OFST_RX2            9
+#define DN_OFST_MAX            0x1F
+
+#define MCPDM_UPLINK           1
+#define MCPDM_DOWNLINK         2
+
+struct omap_mcpdm_link {
+       int irq_mask;
+       int threshold;
+       int format;
+       int channels;
+};
+
+struct omap_mcpdm_platform_data {
+       unsigned long phys_base;
+       u16 irq;
+};
+
+struct omap_mcpdm {
+       struct device *dev;
+       unsigned long phys_base;
+       void __iomem *io_base;
+       u8 free;
+       int irq;
+
+       spinlock_t lock;
+       struct omap_mcpdm_platform_data *pdata;
+       struct clk *clk;
+       struct omap_mcpdm_link *downlink;
+       struct omap_mcpdm_link *uplink;
+       struct completion irq_completion;
+
+       int dn_channels;
+       int up_channels;
+};
+
+extern void omap_mcpdm_start(int stream);
+extern void omap_mcpdm_stop(int stream);
+extern int omap_mcpdm_capture_open(struct omap_mcpdm_link *uplink);
+extern int omap_mcpdm_playback_open(struct omap_mcpdm_link *downlink);
+extern int omap_mcpdm_capture_close(struct omap_mcpdm_link *uplink);
+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);
index 6bbbd2ab0ee7c48f29e79b9ad77d8386dce3da6b..d29725664185d11e8ad419e35b18e25ab896f2dd 100644 (file)
@@ -287,6 +287,8 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
        omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma;
        omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port;
        omap_mcbsp_dai_dma_params[id][substream->stream].sync_mode = sync_mode;
+       omap_mcbsp_dai_dma_params[id][substream->stream].data_type =
+                                                       OMAP_DMA_DATA_TYPE_S16;
        cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream];
 
        if (mcbsp_data->configured) {
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c
new file mode 100644 (file)
index 0000000..25f19e4
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * omap-mcpdm.c  --  OMAP ALSA SoC DAI driver using McPDM port
+ *
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * Author: Misael Lopez Cruz <x0052729@ti.com>
+ * Contact: Jorge Eduardo Candelaria <x0107209@ti.com>
+ *          Margarita Olaya <magi.olaya@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
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#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 {
+       struct omap_mcpdm_link *links;
+       int active;
+};
+
+static struct omap_mcpdm_link omap_mcpdm_links[] = {
+       /* downlink */
+       {
+               .irq_mask = MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL,
+               .threshold = 1,
+               .format = PDMOUTFORMAT_LJUST,
+       },
+       /* uplink */
+       {
+               .irq_mask = MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL,
+               .threshold = 1,
+               .format = PDMOUTFORMAT_LJUST,
+       },
+};
+
+static struct omap_mcpdm_data mcpdm_data = {
+       .links = omap_mcpdm_links,
+       .active = 0,
+};
+
+/*
+ * Stream DMA parameters
+ */
+static struct omap_pcm_dma_data omap_mcpdm_dai_dma_params[] = {
+       {
+               .name = "Audio playback",
+               .dma_req = OMAP44XX_DMA_MCPDM_DL,
+               .data_type = OMAP_DMA_DATA_TYPE_S32,
+               .sync_mode = OMAP_DMA_SYNC_PACKET,
+               .packet_size = 16,
+               .port_addr = OMAP44XX_MCPDM_L3_BASE + MCPDM_DN_DATA,
+       },
+       {
+               .name = "Audio capture",
+               .dma_req = OMAP44XX_DMA_MCPDM_UP,
+               .data_type = OMAP_DMA_DATA_TYPE_S32,
+               .sync_mode = OMAP_DMA_SYNC_PACKET,
+               .packet_size = 16,
+               .port_addr = OMAP44XX_MCPDM_L3_BASE + MCPDM_UP_DATA,
+       },
+};
+
+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)
+               err = omap_mcpdm_request();
+
+       return err;
+}
+
+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)
+               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;
+       int stream = substream->stream;
+       int err = 0;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               if (!mcpdm_priv->active++)
+                       omap_mcpdm_start(stream);
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               if (!--mcpdm_priv->active)
+                       omap_mcpdm_stop(stream);
+               break;
+       default:
+               err = -EINVAL;
+       }
+
+       return err;
+}
+
+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_link *mcpdm_links = mcpdm_priv->links;
+       int stream = substream->stream;
+       int channels, err, link_mask = 0;
+
+       cpu_dai->dma_data = &omap_mcpdm_dai_dma_params[stream];
+
+       channels = params_channels(params);
+       switch (channels) {
+       case 4:
+               if (stream == SNDRV_PCM_STREAM_CAPTURE)
+                       /* up to 2 channels for capture */
+                       return -EINVAL;
+               link_mask |= 1 << 3;
+       case 3:
+               if (stream == SNDRV_PCM_STREAM_CAPTURE)
+                       /* up to 2 channels for capture */
+                       return -EINVAL;
+               link_mask |= 1 << 2;
+       case 2:
+               link_mask |= 1 << 1;
+       case 1:
+               link_mask |= 1 << 0;
+               break;
+       default:
+               /* unsupported number of channels */
+               return -EINVAL;
+       }
+
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               mcpdm_links[stream].channels = link_mask << 3;
+               err = omap_mcpdm_playback_open(&mcpdm_links[stream]);
+       } else {
+               mcpdm_links[stream].channels = link_mask << 0;
+               err = omap_mcpdm_capture_open(&mcpdm_links[stream]);
+       }
+
+       return err;
+}
+
+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_link *mcpdm_links = mcpdm_priv->links;
+       int stream = substream->stream;
+       int err;
+
+       if (substream->stream ==  SNDRV_PCM_STREAM_PLAYBACK)
+               err = omap_mcpdm_playback_close(&mcpdm_links[stream]);
+       else
+               err = omap_mcpdm_capture_close(&mcpdm_links[stream]);
+
+       return err;
+}
+
+static struct snd_soc_dai_ops omap_mcpdm_dai_ops = {
+       .startup        = omap_mcpdm_dai_startup,
+       .shutdown       = omap_mcpdm_dai_shutdown,
+       .trigger        = omap_mcpdm_dai_trigger,
+       .hw_params      = omap_mcpdm_dai_hw_params,
+       .hw_free        = omap_mcpdm_dai_hw_free,
+};
+
+#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,
+       .playback = {
+               .channels_min = 1,
+               .channels_max = 4,
+               .rates = OMAP_MCPDM_RATES,
+               .formats = OMAP_MCPDM_FORMATS,
+       },
+       .capture = {
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = OMAP_MCPDM_RATES,
+               .formats = OMAP_MCPDM_FORMATS,
+       },
+       .ops = &omap_mcpdm_dai_ops,
+       .private_data = &mcpdm_data,
+};
+EXPORT_SYMBOL_GPL(omap_mcpdm_dai);
+
+static int __init snd_omap_mcpdm_init(void)
+{
+       return snd_soc_register_dai(&omap_mcpdm_dai);
+}
+module_init(snd_omap_mcpdm_init);
+
+static void __exit snd_omap_mcpdm_exit(void)
+{
+       snd_soc_unregister_dai(&omap_mcpdm_dai);
+}
+module_exit(snd_omap_mcpdm_exit);
+
+MODULE_AUTHOR("Misael Lopez Cruz <x0052729@ti.com>");
+MODULE_DESCRIPTION("OMAP PDM SoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap-mcpdm.h b/sound/soc/omap/omap-mcpdm.h
new file mode 100644 (file)
index 0000000..73b80d5
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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 9db2770e9640094adeb89b158ea0b6b3da57a366..825db385f01f16d3b0f64a21fbfc3238c801e873 100644 (file)
@@ -37,7 +37,8 @@ static const struct snd_pcm_hardware omap_pcm_hardware = {
                                  SNDRV_PCM_INFO_INTERLEAVED |
                                  SNDRV_PCM_INFO_PAUSE |
                                  SNDRV_PCM_INFO_RESUME,
-       .formats                = SNDRV_PCM_FMTBIT_S16_LE,
+       .formats                = SNDRV_PCM_FMTBIT_S16_LE |
+                                 SNDRV_PCM_FMTBIT_S32_LE,
        .period_bytes_min       = 32,
        .period_bytes_max       = 64 * 1024,
        .periods_min            = 2,
@@ -149,6 +150,7 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream)
        struct omap_runtime_data *prtd = runtime->private_data;
        struct omap_pcm_dma_data *dma_data = prtd->dma_data;
        struct omap_dma_channel_params dma_params;
+       int bytes;
 
        /* return if this is a bufferless transfer e.g.
         * codec <--> BT codec or GSM modem -- lg FIXME */
@@ -156,11 +158,7 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream)
                return 0;
 
        memset(&dma_params, 0, sizeof(dma_params));
-       /*
-        * Note: Regardless of interface data formats supported by OMAP McBSP
-        * or EAC blocks, internal representation is always fixed 16-bit/sample
-        */
-       dma_params.data_type                    = OMAP_DMA_DATA_TYPE_S16;
+       dma_params.data_type                    = dma_data->data_type;
        dma_params.trigger                      = dma_data->dma_req;
        dma_params.sync_mode                    = dma_data->sync_mode;
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -170,6 +168,7 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream)
                dma_params.src_start            = runtime->dma_addr;
                dma_params.dst_start            = dma_data->port_addr;
                dma_params.dst_port             = OMAP_DMA_PORT_MPUI;
+               dma_params.dst_fi               = dma_data->packet_size;
        } else {
                dma_params.src_amode            = OMAP_DMA_AMODE_CONSTANT;
                dma_params.dst_amode            = OMAP_DMA_AMODE_POST_INC;
@@ -177,6 +176,7 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream)
                dma_params.src_start            = dma_data->port_addr;
                dma_params.dst_start            = runtime->dma_addr;
                dma_params.src_port             = OMAP_DMA_PORT_MPUI;
+               dma_params.src_fi               = dma_data->packet_size;
        }
        /*
         * Set DMA transfer frame size equal to ALSA period size and frame
@@ -184,7 +184,8 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream)
         * we can transfer the whole ALSA buffer with single DMA transfer but
         * still can get an interrupt at each period bounary
         */
-       dma_params.elem_count   = snd_pcm_lib_period_bytes(substream) / 2;
+       bytes = snd_pcm_lib_period_bytes(substream);
+       dma_params.elem_count   = bytes >> dma_data->data_type;
        dma_params.frame_count  = runtime->periods;
        omap_set_dma_params(prtd->dma_ch, &dma_params);
 
index 38a821dd4118f6b1411330013945904ce34bf9cb..b19975d269076bcf3b9bc46241846e29e5f26aae 100644 (file)
@@ -29,8 +29,10 @@ struct omap_pcm_dma_data {
        char            *name;          /* stream identifier */
        int             dma_req;        /* DMA request line */
        unsigned long   port_addr;      /* transmit/receive register */
-       int             sync_mode;      /* DMA sync mode */
        void (*set_threshold)(struct snd_pcm_substream *substream);
+       int             data_type;      /* data type 8,16,32 */
+       int             sync_mode;      /* DMA sync mode */
+       int             packet_size;    /* packet size only in PACKET mode */
 };
 
 extern struct snd_soc_platform omap_soc_platform;
index d88ad5ca526c95af030bb6378f58465bcc16b326..240e0975dd6a716e47546a54deb83cecffb9b960 100644 (file)
@@ -117,11 +117,11 @@ static int __init omap3beagle_soc_init(void)
 {
        int ret;
 
-       if (!machine_is_omap3_beagle()) {
-               pr_debug("Not OMAP3 Beagle!\n");
+       if (!(machine_is_omap3_beagle() || machine_is_devkit8000())) {
+               pr_debug("Not OMAP3 Beagle or Devkit8000!\n");
                return -ENODEV;
        }
-       pr_info("OMAP3 Beagle SoC init\n");
+       pr_info("OMAP3 Beagle/Devkit8000 SoC init\n");
 
        omap3beagle_snd_device = platform_device_alloc("soc-audio", -1);
        if (!omap3beagle_snd_device) {
index 68980c19a3bced48ed463460ba9e40454d36fcc4..de10f76badedf7a31d709851789aa7d68b8ee4f5 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
 #include <linux/delay.h>
+#include <linux/regulator/consumer.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -40,6 +41,8 @@
 
 #define PREFIX "ASoC omap3pandora: "
 
+static struct regulator *omap3pandora_dac_reg;
+
 static int omap3pandora_cmn_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params, unsigned int fmt)
 {
@@ -106,21 +109,37 @@ static int omap3pandora_in_hw_params(struct snd_pcm_substream *substream,
                                          SND_SOC_DAIFMT_CBS_CFS);
 }
 
-static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w,
+static int omap3pandora_dac_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *k, int event)
 {
+       /*
+        * The PCM1773 DAC datasheet requires 1ms delay between switching
+        * VCC power on/off and /PD pin high/low
+        */
        if (SND_SOC_DAPM_EVENT_ON(event)) {
+               regulator_enable(omap3pandora_dac_reg);
+               mdelay(1);
                gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 1);
-               gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 1);
        } else {
-               gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 0);
-               mdelay(1);
                gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 0);
+               mdelay(1);
+               regulator_disable(omap3pandora_dac_reg);
        }
 
        return 0;
 }
 
+static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *k, int event)
+{
+       if (SND_SOC_DAPM_EVENT_ON(event))
+               gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 1);
+       else
+               gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 0);
+
+       return 0;
+}
+
 /*
  * Audio paths on Pandora board:
  *
@@ -130,7 +149,9 @@ static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w,
  *  |P| <--- TWL4030 <--------- Line In and MICs
  */
 static const struct snd_soc_dapm_widget omap3pandora_out_dapm_widgets[] = {
-       SND_SOC_DAPM_DAC("PCM DAC", "HiFi Playback", SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_DAC_E("PCM DAC", "HiFi Playback", SND_SOC_NOPM,
+                          0, 0, omap3pandora_dac_event,
+                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
        SND_SOC_DAPM_PGA_E("Headphone Amplifier", SND_SOC_NOPM,
                           0, 0, NULL, 0, omap3pandora_hp_event,
                           SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
@@ -306,8 +327,18 @@ static int __init omap3pandora_soc_init(void)
                goto fail2;
        }
 
+       omap3pandora_dac_reg = regulator_get(&omap3pandora_snd_device->dev, "vcc");
+       if (IS_ERR(omap3pandora_dac_reg)) {
+               pr_err(PREFIX "Failed to get DAC regulator from %s: %ld\n",
+                       dev_name(&omap3pandora_snd_device->dev),
+                       PTR_ERR(omap3pandora_dac_reg));
+               goto fail3;
+       }
+
        return 0;
 
+fail3:
+       platform_device_del(omap3pandora_snd_device);
 fail2:
        platform_device_put(omap3pandora_snd_device);
 fail1:
@@ -320,6 +351,7 @@ module_init(omap3pandora_soc_init);
 
 static void __exit omap3pandora_soc_exit(void)
 {
+       regulator_put(omap3pandora_dac_reg);
        platform_device_unregister(omap3pandora_snd_device);
        gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO);
        gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO);
index 3bd7712f029b9024315bc3cc3f8bf5b6f6988235..e69397f40f72e5306216bf17b6d1f5b3780b5a11 100644 (file)
@@ -135,10 +135,11 @@ static int pxa_ssp_suspend(struct snd_soc_dai *cpu_dai)
        struct ssp_priv *priv = cpu_dai->private_data;
 
        if (!cpu_dai->active)
-               return 0;
+               clk_enable(priv->dev.ssp->clk);
 
        ssp_save_state(&priv->dev, &priv->state);
        clk_disable(priv->dev.ssp->clk);
+
        return 0;
 }
 
@@ -146,12 +147,13 @@ static int pxa_ssp_resume(struct snd_soc_dai *cpu_dai)
 {
        struct ssp_priv *priv = cpu_dai->private_data;
 
-       if (!cpu_dai->active)
-               return 0;
-
        clk_enable(priv->dev.ssp->clk);
        ssp_restore_state(&priv->dev, &priv->state);
-       ssp_enable(&priv->dev);
+
+       if (cpu_dai->active)
+               ssp_enable(&priv->dev);
+       else
+               clk_disable(priv->dev.ssp->clk);
 
        return 0;
 }
index acfce1c0f1c9ee98128472850831a35688cca27b..7e3f41696c41f53e6479a4678982f0bc7e28842d 100644 (file)
@@ -41,7 +41,9 @@ static struct i2c_board_info max9486_hwmon_info = {
 };
 
 #define MAX9485_MCLK_FREQ_112896 0x22
-#define        MAX9485_MCLK_FREQ_122880 0x23
+#define MAX9485_MCLK_FREQ_122880 0x23
+#define MAX9485_MCLK_FREQ_225792 0x32
+#define MAX9485_MCLK_FREQ_245760 0x33
 
 static void set_max9485_clk(char clk)
 {
@@ -71,9 +73,17 @@ 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;
 
-       set_max9485_clk(MAX9485_MCLK_FREQ_112896);
+       /* set freq to 0 to enable all possible codec sample rates */
+       return snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0);
+}
 
-       return snd_soc_dai_set_sysclk(codec_dai, 0, 11289600, 0);
+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;
+
+       /* set freq to 0 to enable all possible codec sample rates */
+       snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0);
 }
 
 static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream,
@@ -86,20 +96,24 @@ static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream,
        int ret = 0;
 
        switch (params_rate(params)) {
-       case 8000:
-       case 16000:
+       case 44100:
+               set_max9485_clk(MAX9485_MCLK_FREQ_112896);
+               clk = 11289600;
+               break;
        case 48000:
-       case 96000:
                set_max9485_clk(MAX9485_MCLK_FREQ_122880);
                clk = 12288000;
                break;
-       case 11025:
-       case 22050:
-       case 44100:
        case 88200:
-               set_max9485_clk(MAX9485_MCLK_FREQ_112896);
-               clk = 11289600;
+               set_max9485_clk(MAX9485_MCLK_FREQ_225792);
+               clk = 22579200;
                break;
+       case 96000:
+               set_max9485_clk(MAX9485_MCLK_FREQ_245760);
+               clk = 24576000;
+               break;
+       default:
+               return -EINVAL;
        }
 
        fmt = SND_SOC_DAIFMT_I2S |
@@ -128,7 +142,7 @@ static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, 0, 1);
+       ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, clk, 1);
        if (ret < 0)
                return ret;
 
@@ -137,6 +151,7 @@ static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream,
 
 static struct snd_soc_ops raumfeld_cs4270_ops = {
        .startup = raumfeld_cs4270_startup,
+       .shutdown = raumfeld_cs4270_shutdown,
        .hw_params = raumfeld_cs4270_hw_params,
 };
 
@@ -181,20 +196,24 @@ static int raumfeld_ak4104_hw_params(struct snd_pcm_substream *substream,
        int fmt, ret = 0, clk = 0;
 
        switch (params_rate(params)) {
-       case 8000:
-       case 16000:
+       case 44100:
+               set_max9485_clk(MAX9485_MCLK_FREQ_112896);
+               clk = 11289600;
+               break;
        case 48000:
-       case 96000:
                set_max9485_clk(MAX9485_MCLK_FREQ_122880);
                clk = 12288000;
                break;
-       case 11025:
-       case 22050:
-       case 44100:
        case 88200:
-               set_max9485_clk(MAX9485_MCLK_FREQ_112896);
-               clk = 11289600;
+               set_max9485_clk(MAX9485_MCLK_FREQ_225792);
+               clk = 22579200;
+               break;
+       case 96000:
+               set_max9485_clk(MAX9485_MCLK_FREQ_245760);
+               clk = 24576000;
                break;
+       default:
+               return -EINVAL;
        }
 
        fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF;
@@ -217,7 +236,7 @@ static int raumfeld_ak4104_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, 0, 1);
+       ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, clk, 1);
        if (ret < 0)
                return ret;
 
index b489f1ae103dfec0c146d1db59d423472defaea4..15fe57e5a232d834b612a9c7df66b2ac6f7a6a46 100644 (file)
@@ -27,12 +27,10 @@ config SND_S3C64XX_SOC_I2S
 config SND_S3C_SOC_PCM
        tristate
 
-config SND_S3C2443_SOC_AC97
+config SND_S3C_SOC_AC97
        tristate
-       select S3C2410_DMA
-       select AC97_BUS
        select SND_SOC_AC97_BUS
-       
+
 config SND_S3C24XX_SOC_NEO1973_WM8753
        tristate "SoC I2S Audio support for NEO1973 - WM8753"
        depends on SND_S3C24XX_SOC && MACH_NEO1973_GTA01
@@ -71,8 +69,10 @@ config SND_S3C64XX_SOC_WM8580
 config SND_S3C24XX_SOC_SMDK2443_WM9710
        tristate "SoC AC97 Audio support for SMDK2443 - WM9710"
        depends on SND_S3C24XX_SOC && MACH_SMDK2443
-       select SND_S3C2443_SOC_AC97
+       select S3C2410_DMA
+       select AC97_BUS
        select SND_SOC_AC97_CODEC
+       select SND_S3C_SOC_AC97
        help
          Say Y if you want to add support for SoC audio on smdk2443
          with the WM9710.
@@ -80,8 +80,10 @@ config SND_S3C24XX_SOC_SMDK2443_WM9710
 config SND_S3C24XX_SOC_LN2440SBC_ALC650
        tristate "SoC AC97 Audio support for LN2440SBC - ALC650"
        depends on SND_S3C24XX_SOC && ARCH_S3C2410
-       select SND_S3C2443_SOC_AC97
+       select S3C2410_DMA
+       select AC97_BUS
        select SND_SOC_AC97_CODEC
+       select SND_S3C_SOC_AC97
        help
          Say Y if you want to add support for SoC audio on ln2440sbc
          with the ALC650.
@@ -111,3 +113,11 @@ config SND_S3C24XX_SOC_SIMTEC_HERMES
        select SND_S3C24XX_SOC_I2S
        select SND_SOC_TLV320AIC3X
        select SND_S3C24XX_SOC_SIMTEC
+
+config SND_SOC_SMDK_WM9713
+       tristate "SoC AC97 Audio support for SMDK with WM9713"
+       depends on SND_S3C24XX_SOC && MACH_SMDK6410
+       select SND_SOC_WM9713
+       select SND_S3C_SOC_AC97
+       help
+         Sat Y if you want to add support for SoC audio on the SMDK.
index b744657733d736f8ad606a14395ee059bf69a812..df071a376fa2fb0f246b67504325bc46b356faa9 100644 (file)
@@ -3,13 +3,13 @@ snd-soc-s3c24xx-objs := s3c-dma.o
 snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
 snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o
 snd-soc-s3c64xx-i2s-objs := s3c64xx-i2s.o
-snd-soc-s3c2443-ac97-objs := s3c2443-ac97.o
+snd-soc-s3c-ac97-objs := s3c-ac97.o
 snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o
 snd-soc-s3c-pcm-objs := s3c-pcm.o
 
 obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o
 obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o
-obj-$(CONFIG_SND_S3C2443_SOC_AC97) += snd-soc-s3c2443-ac97.o
+obj-$(CONFIG_SND_S3C_SOC_AC97) += snd-soc-s3c-ac97.o
 obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o
 obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += snd-soc-s3c64xx-i2s.o
 obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
@@ -26,6 +26,7 @@ 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-smdk64xx-wm8580-objs := smdk64xx_wm8580.o
+snd-soc-smdk-wm9713-objs := smdk_wm9713.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
@@ -37,4 +38,4 @@ 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_S3C64XX_SOC_WM8580) += snd-soc-smdk64xx-wm8580.o
-
+obj-$(CONFIG_SND_SOC_SMDK_WM9713) += snd-soc-smdk-wm9713.o
index d00d359a03e6fd8b30631051b2169474a8a6327f..ffa954fe6931bea522fb02360b8f4877524884bb 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "../codecs/ac97.h"
 #include "s3c-dma.h"
-#include "s3c24xx-ac97.h"
+#include "s3c-ac97.h"
 
 static struct snd_soc_card ln2440sbc;
 
@@ -33,7 +33,7 @@ static struct snd_soc_dai_link ln2440sbc_dai[] = {
 {
        .name = "AC97",
        .stream_name = "AC97 HiFi",
-       .cpu_dai = &s3c2443_ac97_dai[0],
+       .cpu_dai = &s3c_ac97_dai[S3C_AC97_DAI_PCM],
        .codec_dai = &ac97_dai,
 },
 };
diff --git a/sound/soc/s3c24xx/s3c-ac97.c b/sound/soc/s3c24xx/s3c-ac97.c
new file mode 100644 (file)
index 0000000..ee8ed9d
--- /dev/null
@@ -0,0 +1,518 @@
+/* sound/soc/s3c24xx/s3c-ac97.c
+ *
+ * ALSA SoC Audio Layer - S3C AC97 Controller driver
+ *     Evolved from s3c2443-ac97.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd
+ *     Author: Jaswinder Singh <jassi.brar@samsung.com>
+ *     Credits: Graeme Gregory, Sean Choi
+ *
+ * This program is free software; you can 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/io.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <sound/soc.h>
+
+#include <plat/regs-ac97.h>
+#include <mach/dma.h>
+#include <plat/audio.h>
+
+#include "s3c-dma.h"
+#include "s3c-ac97.h"
+
+#define AC_CMD_ADDR(x) (x << 16)
+#define AC_CMD_DATA(x) (x & 0xffff)
+
+struct s3c_ac97_info {
+       unsigned           state;
+       struct clk         *ac97_clk;
+       void __iomem       *regs;
+       struct mutex       lock;
+       struct completion  done;
+};
+static struct s3c_ac97_info s3c_ac97;
+
+static struct s3c2410_dma_client s3c_dma_client_out = {
+       .name = "AC97 PCMOut"
+};
+
+static struct s3c2410_dma_client s3c_dma_client_in = {
+       .name = "AC97 PCMIn"
+};
+
+static struct s3c2410_dma_client s3c_dma_client_micin = {
+       .name = "AC97 MicIn"
+};
+
+static struct s3c_dma_params s3c_ac97_pcm_out = {
+       .client         = &s3c_dma_client_out,
+       .dma_size       = 4,
+};
+
+static struct s3c_dma_params s3c_ac97_pcm_in = {
+       .client         = &s3c_dma_client_in,
+       .dma_size       = 4,
+};
+
+static struct s3c_dma_params s3c_ac97_mic_in = {
+       .client         = &s3c_dma_client_micin,
+       .dma_size       = 4,
+};
+
+static void s3c_ac97_activate(struct snd_ac97 *ac97)
+{
+       u32 ac_glbctrl, stat;
+
+       stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7;
+       if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE)
+               return; /* Return if already active */
+
+       INIT_COMPLETION(s3c_ac97.done);
+
+       ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+       ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON;
+       writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+       msleep(1);
+
+       ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE;
+       writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+       msleep(1);
+
+       ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+       ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
+       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!");
+}
+
+static unsigned short s3c_ac97_read(struct snd_ac97 *ac97,
+       unsigned short reg)
+{
+       u32 ac_glbctrl, ac_codec_cmd;
+       u32 stat, addr, data;
+
+       mutex_lock(&s3c_ac97.lock);
+
+       s3c_ac97_activate(ac97);
+
+       INIT_COMPLETION(s3c_ac97.done);
+
+       ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
+       ac_codec_cmd = S3C_AC97_CODEC_CMD_READ | AC_CMD_ADDR(reg);
+       writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD);
+
+       udelay(50);
+
+       ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+       ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
+       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!");
+
+       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);
+
+       mutex_unlock(&s3c_ac97.lock);
+
+       return (unsigned short)data;
+}
+
+static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+       unsigned short val)
+{
+       u32 ac_glbctrl, ac_codec_cmd;
+
+       mutex_lock(&s3c_ac97.lock);
+
+       s3c_ac97_activate(ac97);
+
+       INIT_COMPLETION(s3c_ac97.done);
+
+       ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
+       ac_codec_cmd = AC_CMD_ADDR(reg) | AC_CMD_DATA(val);
+       writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD);
+
+       udelay(50);
+
+       ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+       ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
+       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!");
+
+       ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
+       ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ;
+       writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD);
+
+       mutex_unlock(&s3c_ac97.lock);
+}
+
+static void s3c_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+       writel(S3C_AC97_GLBCTRL_COLDRESET,
+                       s3c_ac97.regs + S3C_AC97_GLBCTRL);
+       msleep(1);
+
+       writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+       msleep(1);
+}
+
+static void s3c_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+       u32 stat;
+
+       stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7;
+       if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE)
+               return; /* Return if already active */
+
+       writel(S3C_AC97_GLBCTRL_WARMRESET, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+       msleep(1);
+
+       writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+       msleep(1);
+
+       s3c_ac97_activate(ac97);
+}
+
+static irqreturn_t s3c_ac97_irq(int irq, void *dev_id)
+{
+       u32 ac_glbctrl, ac_glbstat;
+
+       ac_glbstat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT);
+
+       if (ac_glbstat & S3C_AC97_GLBSTAT_CODECREADY) {
+
+               ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+               ac_glbctrl &= ~S3C_AC97_GLBCTRL_CODECREADYIE;
+               writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+
+               complete(&s3c_ac97.done);
+       }
+
+       ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+       ac_glbctrl |= (1<<30); /* Clear interrupt */
+       writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+
+       return IRQ_HANDLED;
+}
+
+struct snd_ac97_bus_ops soc_ac97_ops = {
+       .read       = s3c_ac97_read,
+       .write      = s3c_ac97_write,
+       .warm_reset = s3c_ac97_warm_reset,
+       .reset      = s3c_ac97_cold_reset,
+};
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+static int s3c_ac97_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;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               cpu_dai->dma_data = &s3c_ac97_pcm_out;
+       else
+               cpu_dai->dma_data = &s3c_ac97_pcm_in;
+
+       return 0;
+}
+
+static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
+                               struct snd_soc_dai *dai)
+{
+       u32 ac_glbctrl;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       int channel = ((struct s3c_dma_params *)
+                 rtd->dai->cpu_dai->dma_data)->channel;
+
+       ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+               ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK;
+       else
+               ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMOUTTM_MASK;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+                       ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA;
+               else
+                       ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA;
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               break;
+       }
+
+       writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+
+       s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED);
+
+       return 0;
+}
+
+static int s3c_ac97_hw_mic_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;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               return -ENODEV;
+       else
+               cpu_dai->dma_data = &s3c_ac97_mic_in;
+
+       return 0;
+}
+
+static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream,
+                                   int cmd, struct snd_soc_dai *dai)
+{
+       u32 ac_glbctrl;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       int channel = ((struct s3c_dma_params *)
+                 rtd->dai->cpu_dai->dma_data)->channel;
+
+       ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+       ac_glbctrl &= ~S3C_AC97_GLBCTRL_MICINTM_MASK;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               ac_glbctrl |= S3C_AC97_GLBCTRL_MICINTM_DMA;
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               break;
+       }
+
+       writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+
+       s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED);
+
+       return 0;
+}
+
+static struct snd_soc_dai_ops s3c_ac97_dai_ops = {
+       .hw_params      = s3c_ac97_hw_params,
+       .trigger        = s3c_ac97_trigger,
+};
+
+static struct snd_soc_dai_ops s3c_ac97_mic_dai_ops = {
+       .hw_params      = s3c_ac97_hw_mic_params,
+       .trigger        = s3c_ac97_mic_trigger,
+};
+
+struct snd_soc_dai s3c_ac97_dai[] = {
+       [S3C_AC97_DAI_PCM] = {
+               .name = "s3c-ac97",
+               .id = S3C_AC97_DAI_PCM,
+               .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 = &s3c_ac97_dai_ops,
+       },
+       [S3C_AC97_DAI_MIC] = {
+               .name = "s3c-ac97-mic",
+               .id = S3C_AC97_DAI_MIC,
+               .ac97_control = 1,
+               .capture = {
+                       .stream_name = "AC97 Mic Capture",
+                       .channels_min = 1,
+                       .channels_max = 1,
+                       .rates = SNDRV_PCM_RATE_8000_48000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+               .ops = &s3c_ac97_mic_dai_ops,
+       },
+};
+EXPORT_SYMBOL_GPL(s3c_ac97_dai);
+
+static __devinit int s3c_ac97_probe(struct platform_device *pdev)
+{
+       struct resource *mem_res, *dmatx_res, *dmarx_res, *dmamic_res, *irq_res;
+       struct s3c_audio_pdata *ac97_pdata;
+       int ret;
+
+       ac97_pdata = pdev->dev.platform_data;
+       if (!ac97_pdata || !ac97_pdata->cfg_gpio) {
+               dev_err(&pdev->dev, "cfg_gpio callback not provided!\n");
+               return -EINVAL;
+       }
+
+       /* Check for availability of necessary resource */
+       dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+       if (!dmatx_res) {
+               dev_err(&pdev->dev, "Unable to get AC97-TX dma resource\n");
+               return -ENXIO;
+       }
+
+       dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+       if (!dmarx_res) {
+               dev_err(&pdev->dev, "Unable to get AC97-RX dma resource\n");
+               return -ENXIO;
+       }
+
+       dmamic_res = platform_get_resource(pdev, IORESOURCE_DMA, 2);
+       if (!dmamic_res) {
+               dev_err(&pdev->dev, "Unable to get AC97-MIC 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;
+       }
+
+       irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!irq_res) {
+               dev_err(&pdev->dev, "AC97 IRQ not provided!\n");
+               return -ENXIO;
+       }
+
+       if (!request_mem_region(mem_res->start,
+                               resource_size(mem_res), "s3c-ac97")) {
+               dev_err(&pdev->dev, "Unable to request register region\n");
+               return -EBUSY;
+       }
+
+       s3c_ac97_pcm_out.channel = dmatx_res->start;
+       s3c_ac97_pcm_out.dma_addr = mem_res->start + S3C_AC97_PCM_DATA;
+       s3c_ac97_pcm_in.channel = dmarx_res->start;
+       s3c_ac97_pcm_in.dma_addr = mem_res->start + S3C_AC97_PCM_DATA;
+       s3c_ac97_mic_in.channel = dmamic_res->start;
+       s3c_ac97_mic_in.dma_addr = mem_res->start + S3C_AC97_MIC_DATA;
+
+       init_completion(&s3c_ac97.done);
+       mutex_init(&s3c_ac97.lock);
+
+       s3c_ac97.regs = ioremap(mem_res->start, resource_size(mem_res));
+       if (s3c_ac97.regs == NULL) {
+               dev_err(&pdev->dev, "Unable to ioremap register region\n");
+               ret = -ENXIO;
+               goto err1;
+       }
+
+       s3c_ac97.ac97_clk = clk_get(&pdev->dev, "ac97");
+       if (IS_ERR(s3c_ac97.ac97_clk)) {
+               dev_err(&pdev->dev, "s3c-ac97 failed to get ac97_clock\n");
+               ret = -ENODEV;
+               goto err2;
+       }
+       clk_enable(s3c_ac97.ac97_clk);
+
+       if (ac97_pdata->cfg_gpio(pdev)) {
+               dev_err(&pdev->dev, "Unable to configure gpio\n");
+               ret = -EINVAL;
+               goto err3;
+       }
+
+       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");
+               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));
+       if (ret)
+               goto err5;
+
+       return 0;
+
+err5:
+       free_irq(irq_res->start, NULL);
+err4:
+err3:
+       clk_disable(s3c_ac97.ac97_clk);
+       clk_put(s3c_ac97.ac97_clk);
+err2:
+       iounmap(s3c_ac97.regs);
+err1:
+       release_mem_region(mem_res->start, resource_size(mem_res));
+
+       return ret;
+}
+
+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));
+
+       irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (irq_res)
+               free_irq(irq_res->start, NULL);
+
+       clk_disable(s3c_ac97.ac97_clk);
+       clk_put(s3c_ac97.ac97_clk);
+
+       iounmap(s3c_ac97.regs);
+
+       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (mem_res)
+               release_mem_region(mem_res->start, resource_size(mem_res));
+
+       return 0;
+}
+
+static struct platform_driver s3c_ac97_driver = {
+       .probe  = s3c_ac97_probe,
+       .remove = s3c_ac97_remove,
+       .driver = {
+               .name = "s3c-ac97",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init s3c_ac97_init(void)
+{
+       return platform_driver_register(&s3c_ac97_driver);
+}
+module_init(s3c_ac97_init);
+
+static void __exit s3c_ac97_exit(void)
+{
+       platform_driver_unregister(&s3c_ac97_driver);
+}
+module_exit(s3c_ac97_exit);
+
+MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
+MODULE_DESCRIPTION("AC97 driver for the Samsung SoC");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c-ac97.h b/sound/soc/s3c24xx/s3c-ac97.h
new file mode 100644 (file)
index 0000000..2781983
--- /dev/null
@@ -0,0 +1,23 @@
+/* sound/soc/s3c24xx/s3c-ac97.h
+ *
+ * ALSA SoC Audio Layer - S3C AC97 Controller driver
+ *     Evolved from s3c2443-ac97.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd
+ *     Author: Jaswinder Singh <jassi.brar@samsung.com>
+ *     Credits: Graeme Gregory, Sean Choi
+ *
+ * This program is free software; you can 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 __S3C_AC97_H_
+#define __S3C_AC97_H_
+
+#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 9e61a7c2d9ace6680f40ffb2fa221c0a06c30a60..a98f40c3cd291eea98e9a4b9778d5cc5a910c401 100644 (file)
@@ -229,8 +229,7 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
 
        spin_unlock_irqrestore(&pcm->lock, flags);
 
-       dev_dbg(pcm->dev, "PCMSOURCE_CLK-%lu SCLK=%ufs \
-                               SCLK_DIV=%d SYNC_DIV=%d\n",
+       dev_dbg(pcm->dev, "PCMSOURCE_CLK-%lu SCLK=%ufs SCLK_DIV=%d SYNC_DIV=%d\n",
                                clk_get_rate(clk), pcm->sclk_per_fs,
                                sclk_div, sync_div);
 
diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c
deleted file mode 100644 (file)
index 0191e3a..0000000
+++ /dev/null
@@ -1,432 +0,0 @@
-/*
- * s3c2443-ac97.c  --  ALSA Soc Audio Layer
- *
- * (c) 2007 Wolfson Microelectronics PLC.
- * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
- *
- *  Copyright (C) 2005, Sean Choi <sh428.choi@samsung.com>
- *  All rights reserved.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/wait.h>
-#include <linux/delay.h>
-#include <linux/gpio.h>
-#include <linux/clk.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/ac97_codec.h>
-#include <sound/initval.h>
-#include <sound/soc.h>
-
-#include <mach/hardware.h>
-#include <plat/regs-ac97.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-clock.h>
-#include <asm/dma.h>
-#include <mach/dma.h>
-
-#include "s3c-dma.h"
-#include "s3c24xx-ac97.h"
-
-struct s3c24xx_ac97_info {
-       void __iomem    *regs;
-       struct clk      *ac97_clk;
-};
-static struct s3c24xx_ac97_info s3c24xx_ac97;
-
-static DECLARE_COMPLETION(ac97_completion);
-static u32 codec_ready;
-static DEFINE_MUTEX(ac97_mutex);
-
-static unsigned short s3c2443_ac97_read(struct snd_ac97 *ac97,
-       unsigned short reg)
-{
-       u32 ac_glbctrl;
-       u32 ac_codec_cmd;
-       u32 stat, addr, data;
-
-       mutex_lock(&ac97_mutex);
-
-       codec_ready = S3C_AC97_GLBSTAT_CODECREADY;
-       ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
-       ac_codec_cmd = S3C_AC97_CODEC_CMD_READ | AC_CMD_ADDR(reg);
-       writel(ac_codec_cmd, s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
-
-       udelay(50);
-
-       ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
-       ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
-       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
-
-       wait_for_completion(&ac97_completion);
-
-       stat = readl(s3c24xx_ac97.regs + S3C_AC97_STAT);
-       addr = (stat >> 16) & 0x7f;
-       data = (stat & 0xffff);
-
-       if (addr != reg)
-               printk(KERN_ERR "s3c24xx-ac97: req addr = %02x,"
-                               " rep addr = %02x\n", reg, addr);
-
-       mutex_unlock(&ac97_mutex);
-
-       return (unsigned short)data;
-}
-
-static void s3c2443_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
-       unsigned short val)
-{
-       u32 ac_glbctrl;
-       u32 ac_codec_cmd;
-
-       mutex_lock(&ac97_mutex);
-
-       codec_ready = S3C_AC97_GLBSTAT_CODECREADY;
-       ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
-       ac_codec_cmd = AC_CMD_ADDR(reg) | AC_CMD_DATA(val);
-       writel(ac_codec_cmd, s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
-
-       udelay(50);
-
-       ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
-       ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
-       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
-
-       wait_for_completion(&ac97_completion);
-
-       ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
-       ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ;
-       writel(ac_codec_cmd, s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
-
-       mutex_unlock(&ac97_mutex);
-
-}
-
-static void s3c2443_ac97_warm_reset(struct snd_ac97 *ac97)
-{
-       u32 ac_glbctrl;
-
-       ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
-       ac_glbctrl = S3C_AC97_GLBCTRL_WARMRESET;
-       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
-       msleep(1);
-
-       ac_glbctrl = 0;
-       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
-       msleep(1);
-}
-
-static void s3c2443_ac97_cold_reset(struct snd_ac97 *ac97)
-{
-       u32 ac_glbctrl;
-
-       ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
-       ac_glbctrl = S3C_AC97_GLBCTRL_COLDRESET;
-       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
-       msleep(1);
-
-       ac_glbctrl = 0;
-       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
-       msleep(1);
-
-       ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
-       ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON;
-       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
-       msleep(1);
-
-       ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE;
-       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
-       msleep(1);
-
-       ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA |
-               S3C_AC97_GLBCTRL_PCMINTM_DMA | S3C_AC97_GLBCTRL_MICINTM_DMA;
-       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
-}
-
-static irqreturn_t s3c2443_ac97_irq(int irq, void *dev_id)
-{
-       int status;
-       u32 ac_glbctrl;
-
-       status = readl(s3c24xx_ac97.regs + S3C_AC97_GLBSTAT) & codec_ready;
-
-       if (status) {
-               ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
-               ac_glbctrl &= ~S3C_AC97_GLBCTRL_CODECREADYIE;
-               writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
-               complete(&ac97_completion);
-       }
-       return IRQ_HANDLED;
-}
-
-struct snd_ac97_bus_ops soc_ac97_ops = {
-       .read   = s3c2443_ac97_read,
-       .write  = s3c2443_ac97_write,
-       .warm_reset     = s3c2443_ac97_warm_reset,
-       .reset  = s3c2443_ac97_cold_reset,
-};
-
-static struct s3c2410_dma_client s3c2443_dma_client_out = {
-       .name = "AC97 PCM Stereo out"
-};
-
-static struct s3c2410_dma_client s3c2443_dma_client_in = {
-       .name = "AC97 PCM Stereo in"
-};
-
-static struct s3c2410_dma_client s3c2443_dma_client_micin = {
-       .name = "AC97 Mic Mono in"
-};
-
-static struct s3c_dma_params s3c2443_ac97_pcm_stereo_out = {
-       .client         = &s3c2443_dma_client_out,
-       .channel        = DMACH_PCM_OUT,
-       .dma_addr       = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA,
-       .dma_size       = 4,
-};
-
-static struct s3c_dma_params s3c2443_ac97_pcm_stereo_in = {
-       .client         = &s3c2443_dma_client_in,
-       .channel        = DMACH_PCM_IN,
-       .dma_addr       = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA,
-       .dma_size       = 4,
-};
-
-static struct s3c_dma_params s3c2443_ac97_mic_mono_in = {
-       .client         = &s3c2443_dma_client_micin,
-       .channel        = DMACH_MIC_IN,
-       .dma_addr       = S3C2440_PA_AC97 + S3C_AC97_MIC_DATA,
-       .dma_size       = 4,
-};
-
-static int s3c2443_ac97_probe(struct platform_device *pdev,
-                             struct snd_soc_dai *dai)
-{
-       int ret;
-       u32 ac_glbctrl;
-
-       s3c24xx_ac97.regs = ioremap(S3C2440_PA_AC97, 0x100);
-       if (s3c24xx_ac97.regs == NULL)
-               return -ENXIO;
-
-       s3c24xx_ac97.ac97_clk = clk_get(&pdev->dev, "ac97");
-       if (s3c24xx_ac97.ac97_clk == NULL) {
-               printk(KERN_ERR "s3c2443-ac97 failed to get ac97_clock\n");
-               iounmap(s3c24xx_ac97.regs);
-               return -ENODEV;
-       }
-       clk_enable(s3c24xx_ac97.ac97_clk);
-
-       s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2443_GPE0_AC_nRESET);
-       s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2443_GPE1_AC_SYNC);
-       s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2443_GPE2_AC_BITCLK);
-       s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2443_GPE3_AC_SDI);
-       s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2443_GPE4_AC_SDO);
-
-       ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
-       ac_glbctrl = S3C_AC97_GLBCTRL_COLDRESET;
-       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
-       msleep(1);
-
-       ac_glbctrl = 0;
-       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
-       msleep(1);
-
-       ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
-       ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON;
-       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
-       msleep(1);
-
-       ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE;
-       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
-
-       ret = request_irq(IRQ_S3C244x_AC97, s3c2443_ac97_irq,
-               IRQF_DISABLED, "AC97", NULL);
-       if (ret < 0) {
-               printk(KERN_ERR "s3c24xx-ac97: interrupt request failed.\n");
-               clk_disable(s3c24xx_ac97.ac97_clk);
-               clk_put(s3c24xx_ac97.ac97_clk);
-               iounmap(s3c24xx_ac97.regs);
-       }
-       return ret;
-}
-
-static void s3c2443_ac97_remove(struct platform_device *pdev,
-                               struct snd_soc_dai *dai)
-{
-       free_irq(IRQ_S3C244x_AC97, NULL);
-       clk_disable(s3c24xx_ac97.ac97_clk);
-       clk_put(s3c24xx_ac97.ac97_clk);
-       iounmap(s3c24xx_ac97.regs);
-}
-
-static int s3c2443_ac97_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;
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               cpu_dai->dma_data = &s3c2443_ac97_pcm_stereo_out;
-       else
-               cpu_dai->dma_data = &s3c2443_ac97_pcm_stereo_in;
-
-       return 0;
-}
-
-static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
-                               struct snd_soc_dai *dai)
-{
-       u32 ac_glbctrl;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       int channel = ((struct s3c_dma_params *)
-                 rtd->dai->cpu_dai->dma_data)->channel;
-
-       ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-                       ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA;
-               else
-                       ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA;
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-                       ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK;
-               else
-                       ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMOUTTM_MASK;
-               break;
-       }
-       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
-
-       s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED);
-
-       return 0;
-}
-
-static int s3c2443_ac97_hw_mic_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;
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               return -ENODEV;
-       else
-               cpu_dai->dma_data = &s3c2443_ac97_mic_mono_in;
-
-       return 0;
-}
-
-static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream,
-                                   int cmd, struct snd_soc_dai *dai)
-{
-       u32 ac_glbctrl;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       int channel = ((struct s3c_dma_params *)
-                 rtd->dai->cpu_dai->dma_data)->channel;
-
-       ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA;
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK;
-       }
-       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
-
-       s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED);
-
-       return 0;
-}
-
-#define s3c2443_AC97_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)
-
-static struct snd_soc_dai_ops s3c2443_ac97_dai_ops = {
-       .hw_params      = s3c2443_ac97_hw_params,
-       .trigger        = s3c2443_ac97_trigger,
-};
-
-static struct snd_soc_dai_ops s3c2443_ac97_mic_dai_ops = {
-       .hw_params      = s3c2443_ac97_hw_mic_params,
-       .trigger        = s3c2443_ac97_mic_trigger,
-};
-
-struct snd_soc_dai s3c2443_ac97_dai[] = {
-{
-       .name = "s3c2443-ac97",
-       .id = 0,
-       .ac97_control = 1,
-       .probe = s3c2443_ac97_probe,
-       .remove = s3c2443_ac97_remove,
-       .playback = {
-               .stream_name = "AC97 Playback",
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = s3c2443_AC97_RATES,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-       .capture = {
-               .stream_name = "AC97 Capture",
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = s3c2443_AC97_RATES,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-       .ops = &s3c2443_ac97_dai_ops,
-},
-{
-       .name = "pxa2xx-ac97-mic",
-       .id = 1,
-       .ac97_control = 1,
-       .capture = {
-               .stream_name = "AC97 Mic Capture",
-               .channels_min = 1,
-               .channels_max = 1,
-               .rates = s3c2443_AC97_RATES,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-       .ops = &s3c2443_ac97_mic_dai_ops,
-},
-};
-EXPORT_SYMBOL_GPL(s3c2443_ac97_dai);
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
-
-static int __init s3c2443_ac97_init(void)
-{
-       return snd_soc_register_dais(s3c2443_ac97_dai,
-                                    ARRAY_SIZE(s3c2443_ac97_dai));
-}
-module_init(s3c2443_ac97_init);
-
-static void __exit s3c2443_ac97_exit(void)
-{
-       snd_soc_unregister_dais(s3c2443_ac97_dai,
-                               ARRAY_SIZE(s3c2443_ac97_dai));
-}
-module_exit(s3c2443_ac97_exit);
-
-
-MODULE_AUTHOR("Graeme Gregory");
-MODULE_DESCRIPTION("AC97 driver for the Samsung s3c2443 chip");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c24xx-ac97.h b/sound/soc/s3c24xx/s3c24xx-ac97.h
deleted file mode 100644 (file)
index e96f941..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * s3c24xx-ac97.c  --  ALSA Soc Audio Layer
- *
- * (c) 2007 Wolfson Microelectronics PLC.
- * Author: Graeme Gregory
- *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.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.
- *
- *  Revision history
- *    10th Nov 2006   Initial version.
- */
-
-#ifndef S3C24XXAC97_H_
-#define S3C24XXAC97_H_
-
-#define AC_CMD_ADDR(x) (x << 16)
-#define AC_CMD_DATA(x) (x & 0xffff)
-
-extern struct snd_soc_dai s3c2443_ac97_dai[];
-
-#endif /*S3C24XXAC97_H_*/
index cc7edb5f792d86fef69a04ae713587721f2272f9..93ed3aad1631bd2090a5da8bc3af312a6f24b9fa 100644 (file)
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/device.h>
-#include <linux/delay.h>
 #include <linux/clk.h>
-#include <linux/kernel.h>
 #include <linux/gpio.h>
 #include <linux/io.h>
 
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
 #include <sound/soc.h>
 
 #include <plat/regs-s3c2412-iis.h>
 #include "s3c-dma.h"
 #include "s3c64xx-i2s.h"
 
+/* The value should be set to maximum of the total number
+ * of I2Sv3 controllers that any supported SoC has.
+ */
+#define MAX_I2SV3      2
+
 static struct s3c2410_dma_client s3c64xx_dma_client_out = {
        .name           = "I2S PCM Stereo out"
 };
@@ -46,37 +45,12 @@ static struct s3c2410_dma_client s3c64xx_dma_client_in = {
        .name           = "I2S PCM Stereo in"
 };
 
-static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_out[2] = {
-       [0] = {
-               .channel        = DMACH_I2S0_OUT,
-               .client         = &s3c64xx_dma_client_out,
-               .dma_addr       = S3C64XX_PA_IIS0 + S3C2412_IISTXD,
-               .dma_size       = 4,
-       },
-       [1] = {
-               .channel        = DMACH_I2S1_OUT,
-               .client         = &s3c64xx_dma_client_out,
-               .dma_addr       = S3C64XX_PA_IIS1 + S3C2412_IISTXD,
-               .dma_size       = 4,
-       },
-};
-
-static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_in[2] = {
-       [0] = {
-               .channel        = DMACH_I2S0_IN,
-               .client         = &s3c64xx_dma_client_in,
-               .dma_addr       = S3C64XX_PA_IIS0 + S3C2412_IISRXD,
-               .dma_size       = 4,
-       },
-       [1] = {
-               .channel        = DMACH_I2S1_IN,
-               .client         = &s3c64xx_dma_client_in,
-               .dma_addr       = S3C64XX_PA_IIS1 + S3C2412_IISRXD,
-               .dma_size       = 4,
-       },
-};
+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];
 
-static struct s3c_i2sv2_info s3c64xx_i2s[2];
+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)
 {
@@ -169,55 +143,13 @@ static struct snd_soc_dai_ops s3c64xx_i2s_dai_ops = {
        .set_sysclk     = s3c64xx_i2s_set_sysclk,       
 };
 
-struct snd_soc_dai s3c64xx_i2s_dai[] = {
-       {
-               .name           = "s3c64xx-i2s",
-               .id             = 0,
-               .probe          = s3c64xx_i2s_probe,
-               .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",
-               .id             = 1,
-               .probe          = s3c64xx_i2s_probe,
-               .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,
-       },
-};
-EXPORT_SYMBOL_GPL(s3c64xx_i2s_dai);
-
 static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev)
 {
        struct s3c_i2sv2_info *i2s;
        struct snd_soc_dai *dai;
        int ret;
 
-       if (pdev->id >= ARRAY_SIZE(s3c64xx_i2s)) {
+       if (pdev->id >= MAX_I2SV3) {
                dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
                return -EINVAL;
        }
@@ -225,10 +157,40 @@ 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->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;
+       }
+
+       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");
index 12b783b12fcbd3fefa50599156b3d7ea775f3428..362258835e8d9aec20c71c53e8df9a9acf7b6036 100644 (file)
@@ -21,7 +21,7 @@
 
 #include "../codecs/ac97.h"
 #include "s3c-dma.h"
-#include "s3c24xx-ac97.h"
+#include "s3c-ac97.h"
 
 static struct snd_soc_card smdk2443;
 
@@ -29,7 +29,7 @@ static struct snd_soc_dai_link smdk2443_dai[] = {
 {
        .name = "AC97",
        .stream_name = "AC97 HiFi",
-       .cpu_dai = &s3c2443_ac97_dai[0],
+       .cpu_dai = &s3c_ac97_dai[S3C_AC97_DAI_PCM],
        .codec_dai = &ac97_dai,
 },
 };
diff --git a/sound/soc/s3c24xx/smdk_wm9713.c b/sound/soc/s3c24xx/smdk_wm9713.c
new file mode 100644 (file)
index 0000000..24fd39f
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * smdk_wm9713.c  --  SoC audio for SMDK
+ *
+ * Copyright 2010 Samsung Electronics Co. Ltd.
+ * Author: Jaswinder Singh Brar <jassi.brar@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/device.h>
+#include <sound/soc.h>
+
+#include "../codecs/wm9713.h"
+#include "s3c-dma.h"
+#include "s3c-ac97.h"
+
+static struct snd_soc_card smdk;
+
+/*
+ * Default CFG switch settings to use this driver:
+ *
+ *   SMDK6410: Set CFG1 1-3 On, CFG2 1-4 Off
+ */
+
+/*
+ Playback (HeadPhone):-
+       $ amixer sset 'Headphone' unmute
+       $ amixer sset 'Right Headphone Out Mux' 'Headphone'
+       $ amixer sset 'Left Headphone Out Mux' 'Headphone'
+       $ amixer sset 'Right HP Mixer PCM' unmute
+       $ amixer sset 'Left HP Mixer PCM' unmute
+
+ Capture (LineIn):-
+       $ amixer sset 'Right Capture Source' 'Line'
+       $ amixer sset 'Left Capture Source' 'Line'
+*/
+
+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],
+};
+
+static struct snd_soc_card smdk = {
+       .name = "SMDK",
+       .platform = &s3c24xx_soc_platform,
+       .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_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)
+               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_ac97_device);
+       if (ret)
+               platform_device_put(smdk_snd_ac97_device);
+
+       return ret;
+}
+
+static void __exit smdk_exit(void)
+{
+       platform_device_unregister(smdk_snd_ac97_device);
+}
+
+module_init(smdk_init);
+module_exit(smdk_exit);
+
+/* Module information */
+MODULE_AUTHOR("Jaswinder Singh Brar, jassi.brar@samsung.com");
+MODULE_DESCRIPTION("ALSA SoC SMDK+WM9713");
+MODULE_LICENSE("GPL");
index 9e69765865547b98da7043da493a41c8f63f9078..106674979b535a54110ba0b1a0e47048178bb9e9 100644 (file)
@@ -26,6 +26,13 @@ config SND_SOC_SH4_FSI
        help
          This option enables FSI sound support
 
+config SND_SOC_SH4_SIU
+       tristate
+       depends on (SUPERH || ARCH_SHMOBILE) && HAVE_CLK
+       select DMA_ENGINE
+       select DMADEVICES
+       select SH_DMAE
+
 ##
 ## Boards
 ##
@@ -47,4 +54,20 @@ config SND_FSI_AK4642
          This option enables generic sound support for the
          FSI - AK4642 unit
 
+config SND_FSI_DA7210
+       bool "FSI-DA7210 sound support"
+       depends on SND_SOC_SH4_FSI
+       select SND_SOC_DA7210
+       help
+         This option enables generic sound support for the
+         FSI - DA7210 unit
+
+config SND_SIU_MIGOR
+       tristate "SIU sound support on Migo-R"
+       depends on SH_MIGOR
+       select SND_SOC_SH4_SIU
+       select SND_SOC_WM8978
+       help
+         This option enables sound support for the SH7722 Migo-R board
+
 endmenu
index a6997872f24ede65524ee4b83eb31737975f7e21..8a5a19293bda17b7d0ef11fc2a80f385aa23f273 100644 (file)
@@ -6,13 +6,19 @@ obj-$(CONFIG_SND_SOC_PCM_SH7760)      += snd-soc-dma-sh7760.o
 snd-soc-hac-objs       := hac.o
 snd-soc-ssi-objs       := ssi.o
 snd-soc-fsi-objs       := fsi.o
+snd-soc-siu-objs       := siu_pcm.o siu_dai.o
 obj-$(CONFIG_SND_SOC_SH4_HAC)  += snd-soc-hac.o
 obj-$(CONFIG_SND_SOC_SH4_SSI)  += snd-soc-ssi.o
 obj-$(CONFIG_SND_SOC_SH4_FSI)  += snd-soc-fsi.o
+obj-$(CONFIG_SND_SOC_SH4_SIU)  += snd-soc-siu.o
 
 ## boards
 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-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_SIU_MIGOR)    += snd-soc-migor.o
diff --git a/sound/soc/sh/fsi-da7210.c b/sound/soc/sh/fsi-da7210.c
new file mode 100644 (file)
index 0000000..33b4d17
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * fsi-da7210.c
+ *
+ * Copyright (C) 2009 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/io.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/sh_fsi.h>
+#include "../codecs/da7210.h"
+
+static int fsi_da7210_init(struct snd_soc_codec *codec)
+{
+       return snd_soc_dai_set_fmt(&da7210_dai,
+                                  SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                                  SND_SOC_DAIFMT_CBM_CFM);
+}
+
+static struct snd_soc_dai_link fsi_da7210_dai = {
+       .name           = "DA7210",
+       .stream_name    = "DA7210",
+       .cpu_dai        = &fsi_soc_dai[1], /* FSI B */
+       .codec_dai      = &da7210_dai,
+       .init           = fsi_da7210_init,
+};
+
+static struct snd_soc_card fsi_soc_card = {
+       .name           = "FSI",
+       .platform       = &fsi_soc_platform,
+       .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)
+{
+       int ret;
+
+       fsi_da7210_snd_device = platform_device_alloc("soc-audio", -1);
+       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;
+       ret = platform_device_add(fsi_da7210_snd_device);
+       if (ret)
+               platform_device_put(fsi_da7210_snd_device);
+
+       return ret;
+}
+
+static void __exit fsi_da7210_sound_exit(void)
+{
+       platform_device_unregister(fsi_da7210_snd_device);
+}
+
+module_init(fsi_da7210_sound_init);
+module_exit(fsi_da7210_sound_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("ALSA SoC FSI DA2710");
+MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");
+MODULE_LICENSE("GPL");
index 42813b80838988c96b62cf5a91f06d870dbc2f6e..993abb730dfaf92c9d9546045eafcf448148de3c 100644 (file)
@@ -67,6 +67,7 @@
 /* DOFF_ST */
 #define ERR_OVER       0x00000010
 #define ERR_UNDER      0x00000001
+#define ST_ERR         (ERR_OVER | ERR_UNDER)
 
 /* CLK_RST */
 #define B_CLK          0x00000010
@@ -92,6 +93,7 @@
 struct fsi_priv {
        void __iomem *base;
        struct snd_pcm_substream *substream;
+       struct fsi_master *master;
 
        int fifo_max;
        int chan;
@@ -108,10 +110,9 @@ struct fsi_master {
        struct fsi_priv fsia;
        struct fsi_priv fsib;
        struct sh_fsi_platform_info *info;
+       spinlock_t lock;
 };
 
-static struct fsi_master *master;
-
 /************************************************************************
 
 
@@ -119,35 +120,35 @@ static struct fsi_master *master;
 
 
 ************************************************************************/
-static int __fsi_reg_write(u32 reg, u32 data)
+static void __fsi_reg_write(u32 reg, u32 data)
 {
        /* valid data area is 24bit */
        data &= 0x00ffffff;
 
-       return ctrl_outl(data, reg);
+       __raw_writel(data, reg);
 }
 
 static u32 __fsi_reg_read(u32 reg)
 {
-       return ctrl_inl(reg);
+       return __raw_readl(reg);
 }
 
-static int __fsi_reg_mask_set(u32 reg, u32 mask, u32 data)
+static void __fsi_reg_mask_set(u32 reg, u32 mask, u32 data)
 {
        u32 val = __fsi_reg_read(reg);
 
        val &= ~mask;
        val |= data & mask;
 
-       return __fsi_reg_write(reg, val);
+       __fsi_reg_write(reg, val);
 }
 
-static int fsi_reg_write(struct fsi_priv *fsi, u32 reg, u32 data)
+static void fsi_reg_write(struct fsi_priv *fsi, u32 reg, u32 data)
 {
        if (reg > REG_END)
-               return -1;
+               return;
 
-       return __fsi_reg_write((u32)(fsi->base + reg), data);
+       __fsi_reg_write((u32)(fsi->base + reg), data);
 }
 
 static u32 fsi_reg_read(struct fsi_priv *fsi, u32 reg)
@@ -158,39 +159,55 @@ static u32 fsi_reg_read(struct fsi_priv *fsi, u32 reg)
        return __fsi_reg_read((u32)(fsi->base + reg));
 }
 
-static int fsi_reg_mask_set(struct fsi_priv *fsi, u32 reg, u32 mask, u32 data)
+static void fsi_reg_mask_set(struct fsi_priv *fsi, u32 reg, u32 mask, u32 data)
 {
        if (reg > REG_END)
-               return -1;
+               return;
 
-       return __fsi_reg_mask_set((u32)(fsi->base + reg), mask, data);
+       __fsi_reg_mask_set((u32)(fsi->base + reg), mask, data);
 }
 
-static int fsi_master_write(u32 reg, u32 data)
+static void fsi_master_write(struct fsi_master *master, u32 reg, u32 data)
 {
+       unsigned long flags;
+
        if ((reg < MREG_START) ||
            (reg > MREG_END))
-               return -1;
+               return;
 
-       return __fsi_reg_write((u32)(master->base + reg), data);
+       spin_lock_irqsave(&master->lock, flags);
+       __fsi_reg_write((u32)(master->base + reg), data);
+       spin_unlock_irqrestore(&master->lock, flags);
 }
 
-static u32 fsi_master_read(u32 reg)
+static u32 fsi_master_read(struct fsi_master *master, u32 reg)
 {
+       u32 ret;
+       unsigned long flags;
+
        if ((reg < MREG_START) ||
            (reg > MREG_END))
                return 0;
 
-       return __fsi_reg_read((u32)(master->base + reg));
+       spin_lock_irqsave(&master->lock, flags);
+       ret = __fsi_reg_read((u32)(master->base + reg));
+       spin_unlock_irqrestore(&master->lock, flags);
+
+       return ret;
 }
 
-static int fsi_master_mask_set(u32 reg, u32 mask, u32 data)
+static void fsi_master_mask_set(struct fsi_master *master,
+                              u32 reg, u32 mask, u32 data)
 {
+       unsigned long flags;
+
        if ((reg < MREG_START) ||
            (reg > MREG_END))
-               return -1;
+               return;
 
-       return __fsi_reg_mask_set((u32)(master->base + reg), mask, data);
+       spin_lock_irqsave(&master->lock, flags);
+       __fsi_reg_mask_set((u32)(master->base + reg), mask, data);
+       spin_unlock_irqrestore(&master->lock, flags);
 }
 
 /************************************************************************
@@ -200,43 +217,35 @@ static int fsi_master_mask_set(u32 reg, u32 mask, u32 data)
 
 
 ************************************************************************/
-static struct fsi_priv *fsi_get(struct snd_pcm_substream *substream)
+static struct fsi_master *fsi_get_master(struct fsi_priv *fsi)
 {
-       struct snd_soc_pcm_runtime *rtd;
-       struct fsi_priv *fsi = NULL;
+       return fsi->master;
+}
 
-       if (!substream || !master)
-               return NULL;
+static int fsi_is_port_a(struct fsi_priv *fsi)
+{
+       return fsi->master->base == fsi->base;
+}
 
-       rtd = substream->private_data;
-       switch (rtd->dai->cpu_dai->id) {
-       case 0:
-               fsi = &master->fsia;
-               break;
-       case 1:
-               fsi = &master->fsib;
-               break;
-       }
+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 fsi;
+       return  machine->cpu_dai;
 }
 
-static int fsi_is_port_a(struct fsi_priv *fsi)
+static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream)
 {
-       /* return
-        * 1 : port a
-        * 0 : port b
-        */
+       struct snd_soc_dai *dai = fsi_get_dai(substream);
 
-       if (fsi == &master->fsia)
-               return 1;
-
-       return 0;
+       return dai->private_data;
 }
 
 static u32 fsi_get_info_flags(struct fsi_priv *fsi)
 {
        int is_porta = fsi_is_port_a(fsi);
+       struct fsi_master *master = fsi_get_master(fsi);
 
        return is_porta ? master->info->porta_flags :
                master->info->portb_flags;
@@ -314,27 +323,30 @@ static int fsi_get_fifo_residue(struct fsi_priv *fsi, int is_play)
 static void fsi_irq_enable(struct fsi_priv *fsi, int is_play)
 {
        u32 data = fsi_port_ab_io_bit(fsi, is_play);
+       struct fsi_master *master = fsi_get_master(fsi);
 
-       fsi_master_mask_set(IMSK,  data, data);
-       fsi_master_mask_set(IEMSK, data, data);
+       fsi_master_mask_set(master, IMSK,  data, data);
+       fsi_master_mask_set(master, IEMSK, data, data);
 }
 
 static void fsi_irq_disable(struct fsi_priv *fsi, int is_play)
 {
        u32 data = fsi_port_ab_io_bit(fsi, is_play);
+       struct fsi_master *master = fsi_get_master(fsi);
 
-       fsi_master_mask_set(IMSK,  data, 0);
-       fsi_master_mask_set(IEMSK, data, 0);
+       fsi_master_mask_set(master, IMSK,  data, 0);
+       fsi_master_mask_set(master, IEMSK, data, 0);
 }
 
 static void fsi_clk_ctrl(struct fsi_priv *fsi, int enable)
 {
        u32 val = fsi_is_port_a(fsi) ? (1 << 0) : (1 << 4);
+       struct fsi_master *master = fsi_get_master(fsi);
 
        if (enable)
-               fsi_master_mask_set(CLK_RST, val, val);
+               fsi_master_mask_set(master, CLK_RST, val, val);
        else
-               fsi_master_mask_set(CLK_RST, val, 0);
+               fsi_master_mask_set(master, CLK_RST, val, 0);
 }
 
 static void fsi_irq_init(struct fsi_priv *fsi, int is_play)
@@ -355,43 +367,46 @@ static void fsi_irq_init(struct fsi_priv *fsi, int is_play)
        fsi_reg_mask_set(fsi, ctrl, FIFO_CLR, FIFO_CLR);
 
        /* clear interrupt factor */
-       fsi_master_mask_set(INT_ST, data, 0);
+       fsi_master_mask_set(fsi_get_master(fsi), INT_ST, data, 0);
 }
 
-static void fsi_soft_all_reset(void)
+static void fsi_soft_all_reset(struct fsi_master *master)
 {
-       u32 status = fsi_master_read(SOFT_RST);
+       u32 status = fsi_master_read(master, SOFT_RST);
 
        /* port AB reset */
        status &= 0x000000ff;
-       fsi_master_write(SOFT_RST, status);
+       fsi_master_write(master, SOFT_RST, status);
        mdelay(10);
 
        /* soft reset */
        status &= 0x000000f0;
-       fsi_master_write(SOFT_RST, status);
+       fsi_master_write(master, SOFT_RST, status);
        status |= 0x00000001;
-       fsi_master_write(SOFT_RST, status);
+       fsi_master_write(master, SOFT_RST, status);
        mdelay(10);
 }
 
 /* playback interrupt */
-static int fsi_data_push(struct fsi_priv *fsi)
+static int fsi_data_push(struct fsi_priv *fsi, int startup)
 {
        struct snd_pcm_runtime *runtime;
        struct snd_pcm_substream *substream = NULL;
+       u32 status;
        int send;
        int fifo_free;
        int width;
        u8 *start;
-       int i;
+       int i, over_period;
 
        if (!fsi                        ||
            !fsi->substream             ||
            !fsi->substream->runtime)
                return -EINVAL;
 
-       runtime = fsi->substream->runtime;
+       over_period     = 0;
+       substream       = fsi->substream;
+       runtime         = substream->runtime;
 
        /* FSI FIFO has limit.
         * So, this driver can not send periods data at a time
@@ -399,7 +414,7 @@ static int fsi_data_push(struct fsi_priv *fsi)
        if (fsi->byte_offset >=
            fsi->period_len * (fsi->periods + 1)) {
 
-               substream = fsi->substream;
+               over_period = 1;
                fsi->periods = (fsi->periods + 1) % runtime->periods;
 
                if (0 == fsi->periods)
@@ -438,30 +453,44 @@ static int fsi_data_push(struct fsi_priv *fsi)
 
        fsi->byte_offset += send * width;
 
+       status = fsi_reg_read(fsi, DOFF_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, DOFF_ST, 0);
+
        fsi_irq_enable(fsi, 1);
 
-       if (substream)
+       if (over_period)
                snd_pcm_period_elapsed(substream);
 
        return 0;
 }
 
-static int fsi_data_pop(struct fsi_priv *fsi)
+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;
+       int i, over_period;
 
        if (!fsi                        ||
            !fsi->substream             ||
            !fsi->substream->runtime)
                return -EINVAL;
 
-       runtime = fsi->substream->runtime;
+       over_period     = 0;
+       substream       = fsi->substream;
+       runtime         = substream->runtime;
 
        /* FSI FIFO has limit.
         * So, this driver can not send periods data at a time
@@ -469,7 +498,7 @@ static int fsi_data_pop(struct fsi_priv *fsi)
        if (fsi->byte_offset >=
            fsi->period_len * (fsi->periods + 1)) {
 
-               substream = fsi->substream;
+               over_period = 1;
                fsi->periods = (fsi->periods + 1) % runtime->periods;
 
                if (0 == fsi->periods)
@@ -507,9 +536,20 @@ static int fsi_data_pop(struct fsi_priv *fsi)
 
        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 (substream)
+       if (over_period)
                snd_pcm_period_elapsed(substream);
 
        return 0;
@@ -517,23 +557,24 @@ static int fsi_data_pop(struct fsi_priv *fsi)
 
 static irqreturn_t fsi_interrupt(int irq, void *data)
 {
-       u32 status = fsi_master_read(SOFT_RST) & ~0x00000010;
-       u32 int_st = fsi_master_read(INT_ST);
+       struct fsi_master *master = data;
+       u32 status = fsi_master_read(master, SOFT_RST) & ~0x00000010;
+       u32 int_st = fsi_master_read(master, INT_ST);
 
        /* clear irq status */
-       fsi_master_write(SOFT_RST, status);
-       fsi_master_write(SOFT_RST, status | 0x00000010);
+       fsi_master_write(master, SOFT_RST, status);
+       fsi_master_write(master, SOFT_RST, status | 0x00000010);
 
        if (int_st & INT_A_OUT)
-               fsi_data_push(&master->fsia);
+               fsi_data_push(&master->fsia, 0);
        if (int_st & INT_B_OUT)
-               fsi_data_push(&master->fsib);
+               fsi_data_push(&master->fsib, 0);
        if (int_st & INT_A_IN)
-               fsi_data_pop(&master->fsia);
+               fsi_data_pop(&master->fsia, 0);
        if (int_st & INT_B_IN)
-               fsi_data_pop(&master->fsib);
+               fsi_data_pop(&master->fsib, 0);
 
-       fsi_master_write(INT_ST, 0x0000000);
+       fsi_master_write(master, INT_ST, 0x0000000);
 
        return IRQ_HANDLED;
 }
@@ -548,7 +589,7 @@ static irqreturn_t fsi_interrupt(int irq, void *data)
 static int fsi_dai_startup(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
-       struct fsi_priv *fsi = fsi_get(substream);
+       struct fsi_priv *fsi = fsi_get_priv(substream);
        const char *msg;
        u32 flags = fsi_get_info_flags(fsi);
        u32 fmt;
@@ -667,7 +708,7 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
 static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *dai)
 {
-       struct fsi_priv *fsi = fsi_get(substream);
+       struct fsi_priv *fsi = fsi_get_priv(substream);
        int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
 
        fsi_irq_disable(fsi, is_play);
@@ -679,7 +720,7 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
 static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
                           struct snd_soc_dai *dai)
 {
-       struct fsi_priv *fsi = fsi_get(substream);
+       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 ret = 0;
@@ -689,7 +730,7 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
                fsi_stream_push(fsi, substream,
                                frames_to_bytes(runtime, runtime->buffer_size),
                                frames_to_bytes(runtime, runtime->period_size));
-               ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi);
+               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);
@@ -760,7 +801,7 @@ static int fsi_hw_free(struct snd_pcm_substream *substream)
 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(substream);
+       struct fsi_priv *fsi = fsi_get_priv(substream);
        long location;
 
        location = (fsi->byte_offset - 1);
@@ -870,10 +911,16 @@ EXPORT_SYMBOL_GPL(fsi_soc_platform);
 ************************************************************************/
 static int fsi_probe(struct platform_device *pdev)
 {
+       struct fsi_master *master;
        struct resource *res;
        unsigned int irq;
        int ret;
 
+       if (0 != pdev->id) {
+               dev_err(&pdev->dev, "current fsi support id 0 only now\n");
+               return -ENODEV;
+       }
+
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        irq = platform_get_irq(pdev, 0);
        if (!res || (int)irq <= 0) {
@@ -899,15 +946,20 @@ static int fsi_probe(struct platform_device *pdev)
        master->irq             = irq;
        master->info            = pdev->dev.platform_data;
        master->fsia.base       = master->base;
+       master->fsia.master     = master;
        master->fsib.base       = master->base + 0x40;
+       master->fsib.master     = master;
+       spin_lock_init(&master->lock);
 
        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;
 
-       fsi_soft_all_reset();
+       fsi_soft_all_reset(master);
 
        ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, "fsi", master);
        if (ret) {
@@ -937,6 +989,10 @@ exit:
 
 static int fsi_remove(struct platform_device *pdev)
 {
+       struct fsi_master *master;
+
+       master = fsi_get_master(fsi_soc_dai[0].private_data);
+
        snd_soc_unregister_dais(fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai));
        snd_soc_unregister_platform(&fsi_soc_platform);
 
@@ -946,7 +1002,12 @@ static int fsi_remove(struct platform_device *pdev)
 
        iounmap(master->base);
        kfree(master);
-       master = NULL;
+
+       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;
 }
 
diff --git a/sound/soc/sh/migor.c b/sound/soc/sh/migor.c
new file mode 100644 (file)
index 0000000..b823a5c
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * ALSA SoC driver for Migo-R
+ *
+ * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/module.h>
+
+#include <asm/clock.h>
+
+#include <cpu/sh7722.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include "../codecs/wm8978.h"
+#include "siu.h"
+
+/* Default 8000Hz sampling frequency */
+static unsigned long codec_freq = 8000 * 512;
+
+static unsigned int use_count;
+
+/* External clock, sourced from the codec at the SIUMCKB pin */
+static unsigned long siumckb_recalc(struct clk *clk)
+{
+       return codec_freq;
+}
+
+static struct clk_ops siumckb_clk_ops = {
+       .recalc = siumckb_recalc,
+};
+
+static struct clk siumckb_clk = {
+       .name           = "siumckb_clk",
+       .id             = -1,
+       .ops            = &siumckb_clk_ops,
+       .rate           = 0, /* initialised at run-time */
+};
+
+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;
+       int ret;
+       unsigned int rate = params_rate(params);
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8978_PLL, 13000000,
+                                    SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_clkdiv(codec_dai, WM8978_OPCLKRATE, rate * 512);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_NB_IF |
+                                 SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_fmt(rtd->dai->cpu_dai, SND_SOC_DAIFMT_NB_IF |
+                                 SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS);
+       if (ret < 0)
+               return ret;
+
+       codec_freq = rate * 512;
+       /*
+        * This propagates the parent frequency change to children and
+        * recalculates the frequency table
+        */
+       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,
+                                    codec_freq / 2, SND_SOC_CLOCK_IN);
+
+       if (!ret)
+               use_count++;
+
+       return ret;
+}
+
+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;
+
+       if (use_count) {
+               use_count--;
+
+               if (!use_count)
+                       snd_soc_dai_set_sysclk(codec_dai, WM8978_PLL, 0,
+                                              SND_SOC_CLOCK_IN);
+       } else {
+               dev_dbg(codec_dai->dev, "Unbalanced hw_free!\n");
+       }
+
+       return 0;
+}
+
+static struct snd_soc_ops migor_dai_ops = {
+       .hw_params = migor_hw_params,
+       .hw_free = migor_hw_free,
+};
+
+static const struct snd_soc_dapm_widget migor_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone", NULL),
+       SND_SOC_DAPM_MIC("Onboard Microphone", NULL),
+       SND_SOC_DAPM_MIC("External Microphone", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       /* Headphone output connected to LHP/RHP, enable OUT4 for VMID */
+       { "Headphone", NULL,  "OUT4 VMID" },
+       { "OUT4 VMID", NULL,  "LHP" },
+       { "OUT4 VMID", NULL,  "RHP" },
+
+       /* On-board microphone */
+       { "RMICN", NULL, "Mic Bias" },
+       { "RMICP", NULL, "Mic Bias" },
+       { "Mic Bias", NULL, "Onboard Microphone" },
+
+       /* External microphone */
+       { "LMICN", NULL, "Mic Bias" },
+       { "LMICP", NULL, "Mic Bias" },
+       { "Mic Bias", NULL, "External Microphone" },
+};
+
+static int migor_dai_init(struct snd_soc_codec *codec)
+{
+       snd_soc_dapm_new_controls(codec, migor_dapm_widgets,
+                                 ARRAY_SIZE(migor_dapm_widgets));
+
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+       return 0;
+}
+
+/* migor digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link migor_dai = {
+       .name = "wm8978",
+       .stream_name = "WM8978",
+       .cpu_dai = &siu_i2s_dai,
+       .codec_dai = &wm8978_dai,
+       .ops = &migor_dai_ops,
+       .init = migor_dai_init,
+};
+
+/* 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)
+{
+       int ret;
+
+       ret = clk_register(&siumckb_clk);
+       if (ret < 0)
+               return ret;
+
+       /* Port number used on this machine: port B */
+       migor_snd_device = platform_device_alloc("soc-audio", 1);
+       if (!migor_snd_device) {
+               ret = -ENOMEM;
+               goto epdevalloc;
+       }
+
+       platform_set_drvdata(migor_snd_device, &migor_snd_devdata);
+
+       migor_snd_devdata.dev = &migor_snd_device->dev;
+
+       ret = platform_device_add(migor_snd_device);
+       if (ret)
+               goto epdevadd;
+
+       return 0;
+
+epdevadd:
+       platform_device_put(migor_snd_device);
+epdevalloc:
+       clk_unregister(&siumckb_clk);
+       return ret;
+}
+
+static void __exit migor_exit(void)
+{
+       clk_unregister(&siumckb_clk);
+       platform_device_unregister(migor_snd_device);
+}
+
+module_init(migor_init);
+module_exit(migor_exit);
+
+MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
+MODULE_DESCRIPTION("ALSA SoC Migor");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/sh/siu.h b/sound/soc/sh/siu.h
new file mode 100644 (file)
index 0000000..9cc04ab
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * siu.h - ALSA SoC driver for Renesas SH7343, SH7722 SIU peripheral.
+ *
+ * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ * Copyright (C) 2006 Carlos Munoz <carlos@kenati.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef SIU_H
+#define SIU_H
+
+/* Common kernel and user-space firmware-building defines and types */
+
+#define YRAM0_SIZE             (0x0040 / 4)            /* 16 */
+#define YRAM1_SIZE             (0x0080 / 4)            /* 32 */
+#define YRAM2_SIZE             (0x0040 / 4)            /* 16 */
+#define YRAM3_SIZE             (0x0080 / 4)            /* 32 */
+#define YRAM4_SIZE             (0x0080 / 4)            /* 32 */
+#define YRAM_DEF_SIZE          (YRAM0_SIZE + YRAM1_SIZE + YRAM2_SIZE + \
+                                YRAM3_SIZE + YRAM4_SIZE)
+#define YRAM_FIR_SIZE          (0x0400 / 4)            /* 256 */
+#define YRAM_IIR_SIZE          (0x0200 / 4)            /* 128 */
+
+#define XRAM0_SIZE             (0x0400 / 4)            /* 256 */
+#define XRAM1_SIZE             (0x0200 / 4)            /* 128 */
+#define XRAM2_SIZE             (0x0200 / 4)            /* 128 */
+
+/* PRAM program array size */
+#define PRAM0_SIZE             (0x0100 / 4)            /* 64 */
+#define PRAM1_SIZE             ((0x2000 - 0x0100) / 4) /* 1984 */
+
+#include <linux/types.h>
+
+struct siu_spb_param {
+       __u32   ab1a;   /* input FIFO address */
+       __u32   ab0a;   /* output FIFO address */
+       __u32   dir;    /* 0=the ather except CPUOUTPUT, 1=CPUINPUT */
+       __u32   event;  /* SPB program starting conditions */
+       __u32   stfifo; /* STFIFO register setting value */
+       __u32   trdat;  /* TRDAT register setting value */
+};
+
+struct siu_firmware {
+       __u32                   yram_fir_coeff[YRAM_FIR_SIZE];
+       __u32                   pram0[PRAM0_SIZE];
+       __u32                   pram1[PRAM1_SIZE];
+       __u32                   yram0[YRAM0_SIZE];
+       __u32                   yram1[YRAM1_SIZE];
+       __u32                   yram2[YRAM2_SIZE];
+       __u32                   yram3[YRAM3_SIZE];
+       __u32                   yram4[YRAM4_SIZE];
+       __u32                   spbpar_num;
+       struct siu_spb_param    spbpar[32];
+};
+
+#ifdef __KERNEL__
+
+#include <linux/dmaengine.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#include <asm/dma-sh.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc-dai.h>
+
+#define SIU_PERIOD_BYTES_MAX   8192            /* DMA transfer/period size */
+#define SIU_PERIOD_BYTES_MIN   256             /* DMA transfer/period size */
+#define SIU_PERIODS_MAX                64              /* Max periods in buffer */
+#define SIU_PERIODS_MIN                4               /* Min periods in buffer */
+#define SIU_BUFFER_BYTES_MAX   (SIU_PERIOD_BYTES_MAX * SIU_PERIODS_MAX)
+
+/* SIU ports: only one can be used at a time */
+enum {
+       SIU_PORT_A,
+       SIU_PORT_B,
+       SIU_PORT_NUM,
+};
+
+/* SIU clock configuration */
+enum {
+       SIU_CLKA_PLL,
+       SIU_CLKA_EXT,
+       SIU_CLKB_PLL,
+       SIU_CLKB_EXT
+};
+
+struct siu_info {
+       int                     port_id;
+       u32 __iomem             *pram;
+       u32 __iomem             *xram;
+       u32 __iomem             *yram;
+       u32 __iomem             *reg;
+       struct siu_firmware     fw;
+};
+
+struct siu_stream {
+       struct tasklet_struct           tasklet;
+       struct snd_pcm_substream        *substream;
+       snd_pcm_format_t                format;
+       size_t                          buf_bytes;
+       size_t                          period_bytes;
+       int                             cur_period;     /* Period currently in dma */
+       u32                             volume;
+       snd_pcm_sframes_t               xfer_cnt;       /* Number of frames */
+       u8                              rw_flg;         /* transfer status */
+       /* DMA status */
+       struct dma_chan                 *chan;          /* DMA channel */
+       struct dma_async_tx_descriptor  *tx_desc;
+       dma_cookie_t                    cookie;
+       struct sh_dmae_slave            param;
+};
+
+struct siu_port {
+       unsigned long           play_cap;       /* Used to track full duplex */
+       struct snd_pcm          *pcm;
+       struct siu_stream       playback;
+       struct siu_stream       capture;
+       u32                     stfifo;         /* STFIFO value from firmware */
+       u32                     trdat;          /* TRDAT value from firmware */
+};
+
+extern struct siu_port *siu_ports[SIU_PORT_NUM];
+
+static inline struct siu_port *siu_port_info(struct snd_pcm_substream *substream)
+{
+       struct platform_device *pdev =
+               to_platform_device(substream->pcm->card->dev);
+       return siu_ports[pdev->id];
+}
+
+/* Register access */
+static inline void siu_write32(u32 __iomem *addr, u32 val)
+{
+       __raw_writel(val, addr);
+}
+
+static inline u32 siu_read32(u32 __iomem *addr)
+{
+       return __raw_readl(addr);
+}
+
+/* SIU registers */
+#define SIU_IFCTL      (0x000 / sizeof(u32))
+#define SIU_SRCTL      (0x004 / sizeof(u32))
+#define SIU_SFORM      (0x008 / sizeof(u32))
+#define SIU_CKCTL      (0x00c / sizeof(u32))
+#define SIU_TRDAT      (0x010 / sizeof(u32))
+#define SIU_STFIFO     (0x014 / sizeof(u32))
+#define SIU_DPAK       (0x01c / sizeof(u32))
+#define SIU_CKREV      (0x020 / sizeof(u32))
+#define SIU_EVNTC      (0x028 / sizeof(u32))
+#define SIU_SBCTL      (0x040 / sizeof(u32))
+#define SIU_SBPSET     (0x044 / sizeof(u32))
+#define SIU_SBFSTS     (0x068 / sizeof(u32))
+#define SIU_SBDVCA     (0x06c / sizeof(u32))
+#define SIU_SBDVCB     (0x070 / sizeof(u32))
+#define SIU_SBACTIV    (0x074 / sizeof(u32))
+#define SIU_DMAIA      (0x090 / sizeof(u32))
+#define SIU_DMAIB      (0x094 / sizeof(u32))
+#define SIU_DMAOA      (0x098 / sizeof(u32))
+#define SIU_DMAOB      (0x09c / sizeof(u32))
+#define SIU_DMAML      (0x0a0 / sizeof(u32))
+#define SIU_SPSTS      (0x0cc / sizeof(u32))
+#define SIU_SPCTL      (0x0d0 / sizeof(u32))
+#define SIU_BRGASEL    (0x100 / sizeof(u32))
+#define SIU_BRRA       (0x104 / sizeof(u32))
+#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;
+
+int siu_init_port(int port, struct siu_port **port_info, struct snd_card *card);
+void siu_free_port(struct siu_port *port_info);
+
+#endif
+
+#endif /* SIU_H */
diff --git a/sound/soc/sh/siu_dai.c b/sound/soc/sh/siu_dai.c
new file mode 100644 (file)
index 0000000..5452d19
--- /dev/null
@@ -0,0 +1,847 @@
+/*
+ * siu_dai.c - ALSA SoC driver for Renesas SH7343, SH7722 SIU peripheral.
+ *
+ * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ * Copyright (C) 2006 Carlos Munoz <carlos@kenati.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/pm_runtime.h>
+
+#include <asm/clock.h>
+#include <asm/siu.h>
+
+#include <sound/control.h>
+#include <sound/soc-dai.h>
+
+#include "siu.h"
+
+/* Board specifics */
+#if defined(CONFIG_CPU_SUBTYPE_SH7722)
+# define SIU_MAX_VOLUME                0x1000
+#else
+# define SIU_MAX_VOLUME                0x7fff
+#endif
+
+#define PRAM_SIZE      0x2000
+#define XRAM_SIZE      0x800
+#define YRAM_SIZE      0x800
+
+#define XRAM_OFFSET    0x4000
+#define YRAM_OFFSET    0x6000
+#define REG_OFFSET     0xc000
+
+#define PLAYBACK_ENABLED       1
+#define CAPTURE_ENABLED                2
+
+#define VOLUME_CAPTURE         0
+#define VOLUME_PLAYBACK                1
+#define DFLT_VOLUME_LEVEL      0x08000800
+
+/*
+ * SPDIF is only available on port A and on some SIU implementations it is only
+ * available for input. Due to the lack of hardware to test it, SPDIF is left
+ * disabled in this driver version
+ */
+struct format_flag {
+       u32     i2s;
+       u32     pcm;
+       u32     spdif;
+       u32     mask;
+};
+
+struct port_flag {
+       struct format_flag      playback;
+       struct format_flag      capture;
+};
+
+static struct port_flag siu_flags[SIU_PORT_NUM] = {
+       [SIU_PORT_A] = {
+               .playback = {
+                       .i2s    = 0x50000000,
+                       .pcm    = 0x40000000,
+                       .spdif  = 0x80000000,   /* not on all SIU versions */
+                       .mask   = 0xd0000000,
+               },
+               .capture = {
+                       .i2s    = 0x05000000,
+                       .pcm    = 0x04000000,
+                       .spdif  = 0x08000000,
+                       .mask   = 0x0d000000,
+               },
+       },
+       [SIU_PORT_B] = {
+               .playback = {
+                       .i2s    = 0x00500000,
+                       .pcm    = 0x00400000,
+                       .spdif  = 0,            /* impossible - turn off */
+                       .mask   = 0x00500000,
+               },
+               .capture = {
+                       .i2s    = 0x00050000,
+                       .pcm    = 0x00040000,
+                       .spdif  = 0,            /* impossible - turn off */
+                       .mask   = 0x00050000,
+               },
+       },
+};
+
+static void siu_dai_start(struct siu_port *port_info)
+{
+       struct siu_info *info = siu_i2s_dai.private_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);
+
+       /* Issue software reset to siu */
+       siu_write32(base + SIU_SRCTL, 0);
+
+       /* Wait for the reset to take effect */
+       udelay(1);
+
+       port_info->stfifo = 0;
+       port_info->trdat = 0;
+
+       /* portA, portB, SIU operate */
+       siu_write32(base + SIU_SRCTL, 0x301);
+
+       /* portA=256fs, portB=256fs */
+       siu_write32(base + SIU_CKCTL, 0x40400000);
+
+       /* portA's BRG does not divide SIUCKA */
+       siu_write32(base + SIU_BRGASEL, 0);
+       siu_write32(base + SIU_BRRA, 0);
+
+       /* portB's BRG divides SIUCKB by half */
+       siu_write32(base + SIU_BRGBSEL, 1);
+       siu_write32(base + SIU_BRRB, 0);
+
+       siu_write32(base + SIU_IFCTL, 0x44440000);
+
+       /* portA: 32 bit/fs, master; portB: 32 bit/fs, master */
+       siu_write32(base + SIU_SFORM, 0x0c0c0000);
+
+       /*
+        * Volume levels: looks like the DSP firmware implements volume controls
+        * differently from what's described in the datasheet
+        */
+       siu_write32(base + SIU_SBDVCA, port_info->playback.volume);
+       siu_write32(base + SIU_SBDVCB, port_info->capture.volume);
+}
+
+static void siu_dai_stop(void)
+{
+       struct siu_info *info = siu_i2s_dai.private_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);
+}
+
+static void siu_dai_spbAselect(struct siu_port *port_info)
+{
+       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_firmware *fw = &info->fw;
+       u32 *ydef = fw->yram0;
+       u32 idx;
+
+       /* path A use */
+       if (!info->port_id)
+               idx = 1;                /* portA */
+       else
+               idx = 2;                /* portB */
+
+       ydef[0] = (fw->spbpar[idx].ab1a << 16) |
+               (fw->spbpar[idx].ab0a << 8) |
+               (fw->spbpar[idx].dir << 7) | 3;
+       ydef[1] = fw->yram0[1]; /* 0x03000300 */
+       ydef[2] = (16 / 2) << 24;
+       ydef[3] = fw->yram0[3]; /* 0 */
+       ydef[4] = fw->yram0[4]; /* 0 */
+       ydef[7] = fw->spbpar[idx].event;
+       port_info->stfifo |= fw->spbpar[idx].stfifo;
+       port_info->trdat |= fw->spbpar[idx].trdat;
+}
+
+static void siu_dai_spbBselect(struct siu_port *port_info)
+{
+       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_firmware *fw = &info->fw;
+       u32 *ydef = fw->yram0;
+       u32 idx;
+
+       /* path B use */
+       if (!info->port_id)
+               idx = 7;                /* portA */
+       else
+               idx = 8;                /* portB */
+
+       ydef[5] = (fw->spbpar[idx].ab1a << 16) |
+               (fw->spbpar[idx].ab0a << 8) | 1;
+       ydef[6] = fw->spbpar[idx].event;
+       port_info->stfifo |= fw->spbpar[idx].stfifo;
+       port_info->trdat |= fw->spbpar[idx].trdat;
+}
+
+static void siu_dai_open(struct siu_stream *siu_stream)
+{
+       struct siu_info *info = siu_i2s_dai.private_data;
+       u32 __iomem *base = info->reg;
+       u32 srctl, ifctl;
+
+       srctl = siu_read32(base + SIU_SRCTL);
+       ifctl = siu_read32(base + SIU_IFCTL);
+
+       switch (info->port_id) {
+       case SIU_PORT_A:
+               /* portA operates */
+               srctl |= 0x200;
+               ifctl &= ~0xc2;
+               break;
+       case SIU_PORT_B:
+               /* portB operates */
+               srctl |= 0x100;
+               ifctl &= ~0x31;
+               break;
+       }
+
+       siu_write32(base + SIU_SRCTL, srctl);
+       /* Unmute and configure portA */
+       siu_write32(base + SIU_IFCTL, ifctl);
+}
+
+/*
+ * At the moment only fixed Left-upper, Left-lower, Right-upper, Right-lower
+ * packing is supported
+ */
+static void siu_dai_pcmdatapack(struct siu_stream *siu_stream)
+{
+       struct siu_info *info = siu_i2s_dai.private_data;
+       u32 __iomem *base = info->reg;
+       u32 dpak;
+
+       dpak = siu_read32(base + SIU_DPAK);
+
+       switch (info->port_id) {
+       case SIU_PORT_A:
+               dpak &= ~0xc0000000;
+               break;
+       case SIU_PORT_B:
+               dpak &= ~0x00c00000;
+               break;
+       }
+
+       siu_write32(base + SIU_DPAK, dpak);
+}
+
+static int siu_dai_spbstart(struct siu_port *port_info)
+{
+       struct siu_info *info = siu_i2s_dai.private_data;
+       u32 __iomem *base = info->reg;
+       struct siu_firmware *fw = &info->fw;
+       u32 *ydef = fw->yram0;
+       int cnt;
+       u32 __iomem *add;
+       u32 *ptr;
+
+       /* Load SPB Program in PRAM */
+       ptr = fw->pram0;
+       add = info->pram;
+       for (cnt = 0; cnt < PRAM0_SIZE; cnt++, add++, ptr++)
+               siu_write32(add, *ptr);
+
+       ptr = fw->pram1;
+       add = info->pram + (0x0100 / sizeof(u32));
+       for (cnt = 0; cnt < PRAM1_SIZE; cnt++, add++, ptr++)
+               siu_write32(add, *ptr);
+
+       /* XRAM initialization */
+       add = info->xram;
+       for (cnt = 0; cnt < XRAM0_SIZE + XRAM1_SIZE + XRAM2_SIZE; cnt++, add++)
+               siu_write32(add, 0);
+
+       /* YRAM variable area initialization */
+       add = info->yram;
+       for (cnt = 0; cnt < YRAM_DEF_SIZE; cnt++, add++)
+               siu_write32(add, ydef[cnt]);
+
+       /* YRAM FIR coefficient area initialization */
+       add = info->yram + (0x0200 / sizeof(u32));
+       for (cnt = 0; cnt < YRAM_FIR_SIZE; cnt++, add++)
+               siu_write32(add, fw->yram_fir_coeff[cnt]);
+
+       /* YRAM IIR coefficient area initialization */
+       add = info->yram + (0x0600 / sizeof(u32));
+       for (cnt = 0; cnt < YRAM_IIR_SIZE; cnt++, add++)
+               siu_write32(add, 0);
+
+       siu_write32(base + SIU_TRDAT, port_info->trdat);
+       port_info->trdat = 0x0;
+
+
+       /* SPB start condition: software */
+       siu_write32(base + SIU_SBACTIV, 0);
+       /* Start SPB */
+       siu_write32(base + SIU_SBCTL, 0xc0000000);
+       /* Wait for program to halt */
+       cnt = 0x10000;
+       while (--cnt && siu_read32(base + SIU_SBCTL) != 0x80000000)
+               cpu_relax();
+
+       if (!cnt)
+               return -EBUSY;
+
+       /* SPB program start address setting */
+       siu_write32(base + SIU_SBPSET, 0x00400000);
+       /* SPB hardware start(FIFOCTL source) */
+       siu_write32(base + SIU_SBACTIV, 0xc0000000);
+
+       return 0;
+}
+
+static void siu_dai_spbstop(struct siu_port *port_info)
+{
+       struct siu_info *info = siu_i2s_dai.private_data;
+       u32 __iomem *base = info->reg;
+
+       siu_write32(base + SIU_SBACTIV, 0);
+       /* SPB stop */
+       siu_write32(base + SIU_SBCTL, 0);
+
+       port_info->stfifo = 0;
+}
+
+/*             API functions           */
+
+/* Playback and capture hardware properties are identical */
+static struct snd_pcm_hardware siu_dai_pcm_hw = {
+       .info                   = SNDRV_PCM_INFO_INTERLEAVED,
+       .formats                = SNDRV_PCM_FMTBIT_S16,
+       .rates                  = SNDRV_PCM_RATE_8000_48000,
+       .rate_min               = 8000,
+       .rate_max               = 48000,
+       .channels_min           = 2,
+       .channels_max           = 2,
+       .buffer_bytes_max       = SIU_BUFFER_BYTES_MAX,
+       .period_bytes_min       = SIU_PERIOD_BYTES_MIN,
+       .period_bytes_max       = SIU_PERIOD_BYTES_MAX,
+       .periods_min            = SIU_PERIODS_MIN,
+       .periods_max            = SIU_PERIODS_MAX,
+};
+
+static int siu_dai_info_volume(struct snd_kcontrol *kctrl,
+                              struct snd_ctl_elem_info *uinfo)
+{
+       struct siu_port *port_info = snd_kcontrol_chip(kctrl);
+
+       dev_dbg(port_info->pcm->card->dev, "%s\n", __func__);
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = SIU_MAX_VOLUME;
+
+       return 0;
+}
+
+static int siu_dai_get_volume(struct snd_kcontrol *kctrl,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct siu_port *port_info = snd_kcontrol_chip(kctrl);
+       struct device *dev = port_info->pcm->card->dev;
+       u32 vol;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       switch (kctrl->private_value) {
+       case VOLUME_PLAYBACK:
+               /* Playback is always on port 0 */
+               vol = port_info->playback.volume;
+               ucontrol->value.integer.value[0] = vol & 0xffff;
+               ucontrol->value.integer.value[1] = vol >> 16 & 0xffff;
+               break;
+       case VOLUME_CAPTURE:
+               /* Capture is always on port 1 */
+               vol = port_info->capture.volume;
+               ucontrol->value.integer.value[0] = vol & 0xffff;
+               ucontrol->value.integer.value[1] = vol >> 16 & 0xffff;
+               break;
+       default:
+               dev_err(dev, "%s() invalid private_value=%ld\n",
+                       __func__, kctrl->private_value);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int siu_dai_put_volume(struct snd_kcontrol *kctrl,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       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;
+       u32 __iomem *base = info->reg;
+       u32 new_vol;
+       u32 cur_vol;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       if (ucontrol->value.integer.value[0] < 0 ||
+           ucontrol->value.integer.value[0] > SIU_MAX_VOLUME ||
+           ucontrol->value.integer.value[1] < 0 ||
+           ucontrol->value.integer.value[1] > SIU_MAX_VOLUME)
+               return -EINVAL;
+
+       new_vol = ucontrol->value.integer.value[0] |
+               ucontrol->value.integer.value[1] << 16;
+
+       /* See comment above - DSP firmware implementation */
+       switch (kctrl->private_value) {
+       case VOLUME_PLAYBACK:
+               /* Playback is always on port 0 */
+               cur_vol = port_info->playback.volume;
+               siu_write32(base + SIU_SBDVCA, new_vol);
+               port_info->playback.volume = new_vol;
+               break;
+       case VOLUME_CAPTURE:
+               /* Capture is always on port 1 */
+               cur_vol = port_info->capture.volume;
+               siu_write32(base + SIU_SBDVCB, new_vol);
+               port_info->capture.volume = new_vol;
+               break;
+       default:
+               dev_err(dev, "%s() invalid private_value=%ld\n",
+                       __func__, kctrl->private_value);
+               return -EINVAL;
+       }
+
+       if (cur_vol != new_vol)
+               return 1;
+
+       return 0;
+}
+
+static struct snd_kcontrol_new playback_controls = {
+       .iface          = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name           = "PCM Playback Volume",
+       .index          = 0,
+       .info           = siu_dai_info_volume,
+       .get            = siu_dai_get_volume,
+       .put            = siu_dai_put_volume,
+       .private_value  = VOLUME_PLAYBACK,
+};
+
+static struct snd_kcontrol_new capture_controls = {
+       .iface          = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name           = "PCM Capture Volume",
+       .index          = 0,
+       .info           = siu_dai_info_volume,
+       .get            = siu_dai_get_volume,
+       .put            = siu_dai_put_volume,
+       .private_value  = VOLUME_CAPTURE,
+};
+
+int siu_init_port(int port, struct siu_port **port_info, struct snd_card *card)
+{
+       struct device *dev = card->dev;
+       struct snd_kcontrol *kctrl;
+       int ret;
+
+       *port_info = kzalloc(sizeof(**port_info), GFP_KERNEL);
+       if (!*port_info)
+               return -ENOMEM;
+
+       dev_dbg(dev, "%s: port #%d@%p\n", __func__, port, *port_info);
+
+       (*port_info)->playback.volume = DFLT_VOLUME_LEVEL;
+       (*port_info)->capture.volume = DFLT_VOLUME_LEVEL;
+
+       /*
+        * Add mixer support. The SPB is used to change the volume. Both
+        * ports use the same SPB. Therefore, we only register one
+        * control instance since it will be used by both channels.
+        * In error case we continue without controls.
+        */
+       kctrl = snd_ctl_new1(&playback_controls, *port_info);
+       ret = snd_ctl_add(card, kctrl);
+       if (ret < 0)
+               dev_err(dev,
+                       "failed to add playback controls %p port=%d err=%d\n",
+                       kctrl, port, ret);
+
+       kctrl = snd_ctl_new1(&capture_controls, *port_info);
+       ret = snd_ctl_add(card, kctrl);
+       if (ret < 0)
+               dev_err(dev,
+                       "failed to add capture controls %p port=%d err=%d\n",
+                       kctrl, port, ret);
+
+       return 0;
+}
+
+void siu_free_port(struct siu_port *port_info)
+{
+       kfree(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 snd_pcm_runtime *rt = substream->runtime;
+       struct siu_port *port_info = siu_port_info(substream);
+       int ret;
+
+       dev_dbg(substream->pcm->card->dev, "%s: port=%d@%p\n", __func__,
+               info->port_id, port_info);
+
+       snd_soc_set_runtime_hwparams(substream, &siu_dai_pcm_hw);
+
+       ret = snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS);
+       if (unlikely(ret < 0))
+               return ret;
+
+       siu_dai_start(port_info);
+
+       return 0;
+}
+
+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_port *port_info = siu_port_info(substream);
+
+       dev_dbg(substream->pcm->card->dev, "%s: port=%d@%p\n", __func__,
+               info->port_id, port_info);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               port_info->play_cap &= ~PLAYBACK_ENABLED;
+       else
+               port_info->play_cap &= ~CAPTURE_ENABLED;
+
+       /* Stop the siu if the other stream is not using it */
+       if (!port_info->play_cap) {
+               /* during stmread or stmwrite ? */
+               BUG_ON(port_info->playback.rw_flg || port_info->capture.rw_flg);
+               siu_dai_spbstop(port_info);
+               siu_dai_stop();
+       }
+}
+
+/* PCM part of siu_dai_playback_prepare() / siu_dai_capture_prepare() */
+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 snd_pcm_runtime *rt = substream->runtime;
+       struct siu_port *port_info = siu_port_info(substream);
+       struct siu_stream *siu_stream;
+       int self, ret;
+
+       dev_dbg(substream->pcm->card->dev,
+               "%s: port %d, active streams %lx, %d channels\n",
+               __func__, info->port_id, port_info->play_cap, rt->channels);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               self = PLAYBACK_ENABLED;
+               siu_stream = &port_info->playback;
+       } else {
+               self = CAPTURE_ENABLED;
+               siu_stream = &port_info->capture;
+       }
+
+       /* Set up the siu if not already done */
+       if (!port_info->play_cap) {
+               siu_stream->rw_flg = 0; /* stream-data transfer flag */
+
+               siu_dai_spbAselect(port_info);
+               siu_dai_spbBselect(port_info);
+
+               siu_dai_open(siu_stream);
+
+               siu_dai_pcmdatapack(siu_stream);
+
+               ret = siu_dai_spbstart(port_info);
+               if (ret < 0)
+                       goto fail;
+       }
+
+       port_info->play_cap |= self;
+
+fail:
+       return ret;
+}
+
+/*
+ * SIU can set bus format to I2S / PCM / SPDIF independently for playback and
+ * capture, however, the current API sets the bus format globally for a DAI.
+ */
+static int siu_dai_set_fmt(struct snd_soc_dai *dai,
+                          unsigned int fmt)
+{
+       struct siu_info *info = siu_i2s_dai.private_data;
+       u32 __iomem *base = info->reg;
+       u32 ifctl;
+
+       dev_dbg(dai->dev, "%s: fmt 0x%x on port %d\n",
+               __func__, fmt, info->port_id);
+
+       if (info->port_id < 0)
+               return -ENODEV;
+
+       /* Here select between I2S / PCM / SPDIF */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               ifctl = siu_flags[info->port_id].playback.i2s |
+                       siu_flags[info->port_id].capture.i2s;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               ifctl = siu_flags[info->port_id].playback.pcm |
+                       siu_flags[info->port_id].capture.pcm;
+               break;
+       /* SPDIF disabled - see comment at the top */
+       default:
+               return -EINVAL;
+       }
+
+       ifctl |= ~(siu_flags[info->port_id].playback.mask |
+                  siu_flags[info->port_id].capture.mask) &
+               siu_read32(base + SIU_IFCTL);
+       siu_write32(base + SIU_IFCTL, ifctl);
+
+       return 0;
+}
+
+static int siu_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+                             unsigned int freq, int dir)
+{
+       struct clk *siu_clk, *parent_clk;
+       char *siu_name, *parent_name;
+       int ret;
+
+       if (dir != SND_SOC_CLOCK_IN)
+               return -EINVAL;
+
+       dev_dbg(dai->dev, "%s: using clock %d\n", __func__, clk_id);
+
+       switch (clk_id) {
+       case SIU_CLKA_PLL:
+               siu_name = "siua_clk";
+               parent_name = "pll_clk";
+               break;
+       case SIU_CLKA_EXT:
+               siu_name = "siua_clk";
+               parent_name = "siumcka_clk";
+               break;
+       case SIU_CLKB_PLL:
+               siu_name = "siub_clk";
+               parent_name = "pll_clk";
+               break;
+       case SIU_CLKB_EXT:
+               siu_name = "siub_clk";
+               parent_name = "siumckb_clk";
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       siu_clk = clk_get(siu_i2s_dai.dev, siu_name);
+       if (IS_ERR(siu_clk))
+               return PTR_ERR(siu_clk);
+
+       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);
+       }
+
+       clk_put(siu_clk);
+
+       return 0;
+}
+
+static struct snd_soc_dai_ops siu_dai_ops = {
+       .startup        = siu_dai_startup,
+       .shutdown       = siu_dai_shutdown,
+       .prepare        = siu_dai_prepare,
+       .set_sysclk     = siu_dai_set_sysclk,
+       .set_fmt        = siu_dai_set_fmt,
+};
+
+struct snd_soc_dai siu_i2s_dai = {
+       .name = "sh-siu",
+       .id = 0,
+       .playback = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .formats = SNDRV_PCM_FMTBIT_S16,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+       },
+       .capture = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .formats = SNDRV_PCM_FMTBIT_S16,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+        },
+       .ops = &siu_dai_ops,
+};
+EXPORT_SYMBOL_GPL(siu_i2s_dai);
+
+static int __devinit siu_probe(struct platform_device *pdev)
+{
+       const struct firmware *fw_entry;
+       struct resource *res, *region;
+       struct siu_info *info;
+       int ret;
+
+       info = kmalloc(sizeof(*info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       ret = request_firmware(&fw_entry, "siu_spb.bin", &pdev->dev);
+       if (ret)
+               goto ereqfw;
+
+       /*
+        * Loaded firmware is "const" - read only, but we have to modify it in
+        * snd_siu_sh7343_spbAselect() and snd_siu_sh7343_spbBselect()
+        */
+       memcpy(&info->fw, fw_entry->data, fw_entry->size);
+
+       release_firmware(fw_entry);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               ret = -ENODEV;
+               goto egetres;
+       }
+
+       region = request_mem_region(res->start, resource_size(res),
+                                   pdev->name);
+       if (!region) {
+               dev_err(&pdev->dev, "SIU region already claimed\n");
+               ret = -EBUSY;
+               goto ereqmemreg;
+       }
+
+       ret = -ENOMEM;
+       info->pram = ioremap(res->start, PRAM_SIZE);
+       if (!info->pram)
+               goto emappram;
+       info->xram = ioremap(res->start + XRAM_OFFSET, XRAM_SIZE);
+       if (!info->xram)
+               goto emapxram;
+       info->yram = ioremap(res->start + YRAM_OFFSET, YRAM_SIZE);
+       if (!info->yram)
+               goto emapyram;
+       info->reg = ioremap(res->start + REG_OFFSET, resource_size(res) -
+                           REG_OFFSET);
+       if (!info->reg)
+               goto emapreg;
+
+       siu_i2s_dai.dev = &pdev->dev;
+       siu_i2s_dai.private_data = info;
+
+       ret = snd_soc_register_dais(&siu_i2s_dai, 1);
+       if (ret < 0)
+               goto edaiinit;
+
+       ret = snd_soc_register_platform(&siu_platform);
+       if (ret < 0)
+               goto esocregp;
+
+       pm_runtime_enable(&pdev->dev);
+
+       return ret;
+
+esocregp:
+       snd_soc_unregister_dais(&siu_i2s_dai, 1);
+edaiinit:
+       iounmap(info->reg);
+emapreg:
+       iounmap(info->yram);
+emapyram:
+       iounmap(info->xram);
+emapxram:
+       iounmap(info->pram);
+emappram:
+       release_mem_region(res->start, resource_size(res));
+ereqmemreg:
+egetres:
+ereqfw:
+       kfree(info);
+
+       return ret;
+}
+
+static int __devexit siu_remove(struct platform_device *pdev)
+{
+       struct siu_info *info = siu_i2s_dai.private_data;
+       struct resource *res;
+
+       pm_runtime_disable(&pdev->dev);
+
+       snd_soc_unregister_platform(&siu_platform);
+       snd_soc_unregister_dais(&siu_i2s_dai, 1);
+
+       iounmap(info->reg);
+       iounmap(info->yram);
+       iounmap(info->xram);
+       iounmap(info->pram);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res)
+               release_mem_region(res->start, resource_size(res));
+       kfree(info);
+
+       return 0;
+}
+
+static struct platform_driver siu_driver = {
+       .driver         = {
+               .name   = "sh_siu",
+       },
+       .probe          = siu_probe,
+       .remove         = __devexit_p(siu_remove),
+};
+
+static int __init siu_init(void)
+{
+       return platform_driver_register(&siu_driver);
+}
+
+static void __exit siu_exit(void)
+{
+       platform_driver_unregister(&siu_driver);
+}
+
+module_init(siu_init)
+module_exit(siu_exit)
+
+MODULE_AUTHOR("Carlos Munoz <carlos@kenati.com>");
+MODULE_DESCRIPTION("ALSA SoC SH7722 SIU driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c
new file mode 100644 (file)
index 0000000..c5efc30
--- /dev/null
@@ -0,0 +1,616 @@
+/*
+ * siu_pcm.c - ALSA driver for Renesas SH7343, SH7722 SIU peripheral.
+ *
+ * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ * Copyright (C) 2006 Carlos Munoz <carlos@kenati.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-dai.h>
+
+#include <asm/dma-sh.h>
+#include <asm/siu.h>
+
+#include "siu.h"
+
+#define GET_MAX_PERIODS(buf_bytes, period_bytes) \
+                               ((buf_bytes) / (period_bytes))
+#define PERIOD_OFFSET(buf_addr, period_num, period_bytes) \
+                               ((buf_addr) + ((period_num) * (period_bytes)))
+
+#define RWF_STM_RD             0x01            /* Read in progress */
+#define RWF_STM_WT             0x02            /* Write in progress */
+
+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;
+       u32 __iomem *base = info->reg;
+       struct siu_stream *siu_stream = &port_info->playback;
+       u32 stfifo;
+
+       if (!siu_stream->rw_flg)
+               return -EPERM;
+
+       /* output FIFO disable */
+       stfifo = siu_read32(base + SIU_STFIFO);
+       siu_write32(base + SIU_STFIFO, stfifo & ~0x0c180c18);
+       pr_debug("%s: STFIFO %x -> %x\n", __func__,
+                stfifo, stfifo & ~0x0c180c18);
+
+       /* during stmwrite clear */
+       siu_stream->rw_flg = 0;
+
+       return 0;
+}
+
+static int siu_pcm_stmwrite_start(struct siu_port *port_info)
+{
+       struct siu_stream *siu_stream = &port_info->playback;
+
+       if (siu_stream->rw_flg)
+               return -EPERM;
+
+       /* Current period in buffer */
+       port_info->playback.cur_period = 0;
+
+       /* during stmwrite flag set */
+       siu_stream->rw_flg = RWF_STM_WT;
+
+       /* DMA transfer start */
+       tasklet_schedule(&siu_stream->tasklet);
+
+       return 0;
+}
+
+static void siu_dma_tx_complete(void *arg)
+{
+       struct siu_stream *siu_stream = arg;
+
+       if (!siu_stream->rw_flg)
+               return;
+
+       /* Update completed period count */
+       if (++siu_stream->cur_period >=
+           GET_MAX_PERIODS(siu_stream->buf_bytes,
+                           siu_stream->period_bytes))
+               siu_stream->cur_period = 0;
+
+       pr_debug("%s: done period #%d (%u/%u bytes), cookie %d\n",
+               __func__, siu_stream->cur_period,
+               siu_stream->cur_period * siu_stream->period_bytes,
+               siu_stream->buf_bytes, siu_stream->cookie);
+
+       tasklet_schedule(&siu_stream->tasklet);
+
+       /* Notify alsa: a period is done */
+       snd_pcm_period_elapsed(siu_stream->substream);
+}
+
+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;
+       u32 __iomem *base = info->reg;
+       struct siu_stream *siu_stream = &port_info->playback;
+       struct snd_pcm_substream *substream = siu_stream->substream;
+       struct device *dev = substream->pcm->card->dev;
+       struct dma_async_tx_descriptor *desc;
+       dma_cookie_t cookie;
+       struct scatterlist sg;
+       u32 stfifo;
+
+       sg_init_table(&sg, 1);
+       sg_set_page(&sg, pfn_to_page(PFN_DOWN(buff)),
+                   size, offset_in_page(buff));
+       sg_dma_address(&sg) = buff;
+
+       desc = siu_stream->chan->device->device_prep_slave_sg(siu_stream->chan,
+               &sg, 1, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!desc) {
+               dev_err(dev, "Failed to allocate a dma descriptor\n");
+               return -ENOMEM;
+       }
+
+       desc->callback = siu_dma_tx_complete;
+       desc->callback_param = siu_stream;
+       cookie = desc->tx_submit(desc);
+       if (cookie < 0) {
+               dev_err(dev, "Failed to submit a dma transfer\n");
+               return cookie;
+       }
+
+       siu_stream->tx_desc = desc;
+       siu_stream->cookie = cookie;
+
+       dma_async_issue_pending(siu_stream->chan);
+
+       /* only output FIFO enable */
+       stfifo = siu_read32(base + SIU_STFIFO);
+       siu_write32(base + SIU_STFIFO, stfifo | (port_info->stfifo & 0x0c180c18));
+       dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__,
+               stfifo, stfifo | (port_info->stfifo & 0x0c180c18));
+
+       return 0;
+}
+
+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;
+       u32 __iomem *base = info->reg;
+       struct siu_stream *siu_stream = &port_info->capture;
+       struct snd_pcm_substream *substream = siu_stream->substream;
+       struct device *dev = substream->pcm->card->dev;
+       struct dma_async_tx_descriptor *desc;
+       dma_cookie_t cookie;
+       struct scatterlist sg;
+       u32 stfifo;
+
+       dev_dbg(dev, "%s: %u@%llx\n", __func__, size, (unsigned long long)buff);
+
+       sg_init_table(&sg, 1);
+       sg_set_page(&sg, pfn_to_page(PFN_DOWN(buff)),
+                   size, offset_in_page(buff));
+       sg_dma_address(&sg) = buff;
+
+       desc = siu_stream->chan->device->device_prep_slave_sg(siu_stream->chan,
+               &sg, 1, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!desc) {
+               dev_err(dev, "Failed to allocate dma descriptor\n");
+               return -ENOMEM;
+       }
+
+       desc->callback = siu_dma_tx_complete;
+       desc->callback_param = siu_stream;
+       cookie = desc->tx_submit(desc);
+       if (cookie < 0) {
+               dev_err(dev, "Failed to submit dma descriptor\n");
+               return cookie;
+       }
+
+       siu_stream->tx_desc = desc;
+       siu_stream->cookie = cookie;
+
+       dma_async_issue_pending(siu_stream->chan);
+
+       /* only input FIFO enable */
+       stfifo = siu_read32(base + SIU_STFIFO);
+       siu_write32(base + SIU_STFIFO, siu_read32(base + SIU_STFIFO) |
+                   (port_info->stfifo & 0x13071307));
+       dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__,
+               stfifo, stfifo | (port_info->stfifo & 0x13071307));
+
+       return 0;
+}
+
+static void siu_io_tasklet(unsigned long data)
+{
+       struct siu_stream *siu_stream = (struct siu_stream *)data;
+       struct snd_pcm_substream *substream = siu_stream->substream;
+       struct device *dev = substream->pcm->card->dev;
+       struct snd_pcm_runtime *rt = substream->runtime;
+       struct siu_port *port_info = siu_port_info(substream);
+
+       dev_dbg(dev, "%s: flags %x\n", __func__, siu_stream->rw_flg);
+
+       if (!siu_stream->rw_flg) {
+               dev_dbg(dev, "%s: stream inactive\n", __func__);
+               return;
+       }
+
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+               dma_addr_t buff;
+               size_t count;
+               u8 *virt;
+
+               buff = (dma_addr_t)PERIOD_OFFSET(rt->dma_addr,
+                                               siu_stream->cur_period,
+                                               siu_stream->period_bytes);
+               virt = PERIOD_OFFSET(rt->dma_area,
+                                    siu_stream->cur_period,
+                                    siu_stream->period_bytes);
+               count = siu_stream->period_bytes;
+
+               /* DMA transfer start */
+               siu_pcm_rd_set(port_info, buff, count);
+       } else {
+               siu_pcm_wr_set(port_info,
+                              (dma_addr_t)PERIOD_OFFSET(rt->dma_addr,
+                                               siu_stream->cur_period,
+                                               siu_stream->period_bytes),
+                              siu_stream->period_bytes);
+       }
+}
+
+/* Capture */
+static int siu_pcm_stmread_start(struct siu_port *port_info)
+{
+       struct siu_stream *siu_stream = &port_info->capture;
+
+       if (siu_stream->xfer_cnt > 0x1000000)
+               return -EINVAL;
+       if (siu_stream->rw_flg)
+               return -EPERM;
+
+       /* Current period in buffer */
+       siu_stream->cur_period = 0;
+
+       /* during stmread flag set */
+       siu_stream->rw_flg = RWF_STM_RD;
+
+       tasklet_schedule(&siu_stream->tasklet);
+
+       return 0;
+}
+
+static int siu_pcm_stmread_stop(struct siu_port *port_info)
+{
+       struct siu_info *info = siu_i2s_dai.private_data;
+       u32 __iomem *base = info->reg;
+       struct siu_stream *siu_stream = &port_info->capture;
+       struct device *dev = siu_stream->substream->pcm->card->dev;
+       u32 stfifo;
+
+       if (!siu_stream->rw_flg)
+               return -EPERM;
+
+       /* input FIFO disable */
+       stfifo = siu_read32(base + SIU_STFIFO);
+       siu_write32(base + SIU_STFIFO, stfifo & ~0x13071307);
+       dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__,
+               stfifo, stfifo & ~0x13071307);
+
+       /* during stmread flag clear */
+       siu_stream->rw_flg = 0;
+
+       return 0;
+}
+
+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 device *dev = ss->pcm->card->dev;
+       int ret;
+
+       dev_dbg(dev, "%s: port=%d\n", __func__, info->port_id);
+
+       ret = snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(hw_params));
+       if (ret < 0)
+               dev_err(dev, "snd_pcm_lib_malloc_pages() failed\n");
+
+       return ret;
+}
+
+static int siu_pcm_hw_free(struct snd_pcm_substream *ss)
+{
+       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_port *port_info = siu_port_info(ss);
+       struct device *dev = ss->pcm->card->dev;
+       struct siu_stream *siu_stream;
+
+       if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               siu_stream = &port_info->playback;
+       else
+               siu_stream = &port_info->capture;
+
+       dev_dbg(dev, "%s: port=%d\n", __func__, info->port_id);
+
+       return snd_pcm_lib_free_pages(ss);
+}
+
+static bool filter(struct dma_chan *chan, void *slave)
+{
+       struct sh_dmae_slave *param = slave;
+
+       pr_debug("%s: slave ID %d\n", __func__, param->slave_id);
+
+       if (unlikely(param->dma_dev != chan->device->dev))
+               return false;
+
+       chan->private = param;
+       return true;
+}
+
+static int siu_pcm_open(struct snd_pcm_substream *ss)
+{
+       /* Playback / Capture */
+       struct siu_info *info = siu_i2s_dai.private_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;
+
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+
+       dev_dbg(dev, "%s, port=%d@%p\n", __func__, port, port_info);
+
+       if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               siu_stream = &port_info->playback;
+               param = &siu_stream->param;
+               param->slave_id = port ? SHDMA_SLAVE_SIUB_TX :
+                       SHDMA_SLAVE_SIUA_TX;
+       } else {
+               siu_stream = &port_info->capture;
+               param = &siu_stream->param;
+               param->slave_id = port ? SHDMA_SLAVE_SIUB_RX :
+                       SHDMA_SLAVE_SIUA_RX;
+       }
+
+       param->dma_dev = pdata->dma_dev;
+       /* Get DMA channel */
+       siu_stream->chan = dma_request_channel(mask, filter, param);
+       if (!siu_stream->chan) {
+               dev_err(dev, "DMA channel allocation failed!\n");
+               return -EBUSY;
+       }
+
+       siu_stream->substream = ss;
+
+       return 0;
+}
+
+static int siu_pcm_close(struct snd_pcm_substream *ss)
+{
+       struct siu_info *info = siu_i2s_dai.private_data;
+       struct device *dev = ss->pcm->card->dev;
+       struct siu_port *port_info = siu_port_info(ss);
+       struct siu_stream *siu_stream;
+
+       dev_dbg(dev, "%s: port=%d\n", __func__, info->port_id);
+
+       if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               siu_stream = &port_info->playback;
+       else
+               siu_stream = &port_info->capture;
+
+       dma_release_channel(siu_stream->chan);
+       siu_stream->chan = NULL;
+
+       siu_stream->substream = NULL;
+
+       return 0;
+}
+
+static int siu_pcm_prepare(struct snd_pcm_substream *ss)
+{
+       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_port *port_info = siu_port_info(ss);
+       struct device *dev = ss->pcm->card->dev;
+       struct snd_pcm_runtime  *rt = ss->runtime;
+       struct siu_stream *siu_stream;
+       snd_pcm_sframes_t xfer_cnt;
+
+       if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               siu_stream = &port_info->playback;
+       else
+               siu_stream = &port_info->capture;
+
+       rt = siu_stream->substream->runtime;
+
+       siu_stream->buf_bytes = snd_pcm_lib_buffer_bytes(ss);
+       siu_stream->period_bytes = snd_pcm_lib_period_bytes(ss);
+
+       dev_dbg(dev, "%s: port=%d, %d channels, period=%u bytes\n", __func__,
+               info->port_id, rt->channels, siu_stream->period_bytes);
+
+       /* We only support buffers that are multiples of the period */
+       if (siu_stream->buf_bytes % siu_stream->period_bytes) {
+               dev_err(dev, "%s() - buffer=%d not multiple of period=%d\n",
+                      __func__, siu_stream->buf_bytes,
+                      siu_stream->period_bytes);
+               return -EINVAL;
+       }
+
+       xfer_cnt = bytes_to_frames(rt, siu_stream->period_bytes);
+       if (!xfer_cnt || xfer_cnt > 0x1000000)
+               return -EINVAL;
+
+       siu_stream->format = rt->format;
+       siu_stream->xfer_cnt = xfer_cnt;
+
+       dev_dbg(dev, "port=%d buf=%lx buf_bytes=%d period_bytes=%d "
+               "format=%d channels=%d xfer_cnt=%d\n", info->port_id,
+               (unsigned long)rt->dma_addr, siu_stream->buf_bytes,
+               siu_stream->period_bytes,
+               siu_stream->format, rt->channels, (int)xfer_cnt);
+
+       return 0;
+}
+
+static int siu_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
+{
+       struct siu_info *info = siu_i2s_dai.private_data;
+       struct device *dev = ss->pcm->card->dev;
+       struct siu_port *port_info = siu_port_info(ss);
+       int ret;
+
+       dev_dbg(dev, "%s: port=%d@%p, cmd=%d\n", __func__,
+               info->port_id, port_info, cmd);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       ret = siu_pcm_stmwrite_start(port_info);
+               else
+                       ret = siu_pcm_stmread_start(port_info);
+
+               if (ret < 0)
+                       dev_warn(dev, "%s: start failed on port=%d\n",
+                                __func__, info->port_id);
+
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       siu_pcm_stmwrite_stop(port_info);
+               else
+                       siu_pcm_stmread_stop(port_info);
+               ret = 0;
+
+               break;
+       default:
+               dev_err(dev, "%s() unsupported cmd=%d\n", __func__, cmd);
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+/*
+ * So far only resolution of one period is supported, subject to extending the
+ * dmangine API
+ */
+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;
+       u32 __iomem *base = info->reg;
+       struct siu_port *port_info = siu_port_info(ss);
+       struct snd_pcm_runtime *rt = ss->runtime;
+       size_t ptr;
+       struct siu_stream *siu_stream;
+
+       if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               siu_stream = &port_info->playback;
+       else
+               siu_stream = &port_info->capture;
+
+       /*
+        * ptr is the offset into the buffer where the dma is currently at. We
+        * check if the dma buffer has just wrapped.
+        */
+       ptr = PERIOD_OFFSET(rt->dma_addr,
+                           siu_stream->cur_period,
+                           siu_stream->period_bytes) - rt->dma_addr;
+
+       dev_dbg(dev,
+               "%s: port=%d, events %x, FSTS %x, xferred %u/%u, cookie %d\n",
+               __func__, info->port_id, siu_read32(base + SIU_EVNTC),
+               siu_read32(base + SIU_SBFSTS), ptr, siu_stream->buf_bytes,
+               siu_stream->cookie);
+
+       if (ptr >= siu_stream->buf_bytes)
+               ptr = 0;
+
+       return bytes_to_frames(ss->runtime, ptr);
+}
+
+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 platform_device *pdev = to_platform_device(card->dev);
+       int ret;
+       int i;
+
+       /* pdev->id selects between SIUA and SIUB */
+       if (pdev->id < 0 || pdev->id >= SIU_PORT_NUM)
+               return -EINVAL;
+
+       info->port_id = pdev->id;
+
+       /*
+        * While the siu has 2 ports, only one port can be on at a time (only 1
+        * SPB). So far all the boards using the siu had only one of the ports
+        * wired to a codec. To simplify things, we only register one port with
+        * alsa. In case both ports are needed, it should be changed here
+        */
+       for (i = pdev->id; i < pdev->id + 1; i++) {
+               struct siu_port **port_info = &siu_ports[i];
+
+               ret = siu_init_port(i, port_info, card);
+               if (ret < 0)
+                       return ret;
+
+               ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
+                               SNDRV_DMA_TYPE_DEV, NULL,
+                               SIU_BUFFER_BYTES_MAX, SIU_BUFFER_BYTES_MAX);
+               if (ret < 0) {
+                       dev_err(card->dev,
+                              "snd_pcm_lib_preallocate_pages_for_all() err=%d",
+                               ret);
+                       goto fail;
+               }
+
+               (*port_info)->pcm = pcm;
+
+               /* IO tasklets */
+               tasklet_init(&(*port_info)->playback.tasklet, siu_io_tasklet,
+                            (unsigned long)&(*port_info)->playback);
+               tasklet_init(&(*port_info)->capture.tasklet, siu_io_tasklet,
+                            (unsigned long)&(*port_info)->capture);
+       }
+
+       dev_info(card->dev, "SuperH SIU driver initialized.\n");
+       return 0;
+
+fail:
+       siu_free_port(siu_ports[pdev->id]);
+       dev_err(card->dev, "SIU: failed to initialize.\n");
+       return ret;
+}
+
+static void siu_pcm_free(struct snd_pcm *pcm)
+{
+       struct platform_device *pdev = to_platform_device(pcm->card->dev);
+       struct siu_port *port_info = siu_ports[pdev->id];
+
+       tasklet_kill(&port_info->capture.tasklet);
+       tasklet_kill(&port_info->playback.tasklet);
+
+       siu_free_port(port_info);
+       snd_pcm_lib_preallocate_free_for_all(pcm);
+
+       dev_dbg(pcm->card->dev, "%s\n", __func__);
+}
+
+static struct snd_pcm_ops siu_pcm_ops = {
+       .open           = siu_pcm_open,
+       .close          = siu_pcm_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = siu_pcm_hw_params,
+       .hw_free        = siu_pcm_hw_free,
+       .prepare        = siu_pcm_prepare,
+       .trigger        = siu_pcm_trigger,
+       .pointer        = siu_pcm_pointer_dma,
+};
+
+struct snd_soc_platform siu_platform = {
+       .name           = "siu-audio",
+       .pcm_ops        = &siu_pcm_ops,
+       .pcm_new        = siu_pcm_new,
+       .pcm_free       = siu_pcm_free,
+};
+EXPORT_SYMBOL_GPL(siu_platform);
index d2505e8b06c9783dcb89a6226f7f2e3393c6bf63..5869dc3be7815cc6cbadb03165c2f9d84d4dae86 100644 (file)
 #include <linux/spi/spi.h>
 #include <sound/soc.h>
 
+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;
+       return cache[reg];
+}
+
+static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
+                            unsigned int value)
+{
+       u16 *cache = codec->reg_cache;
+       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 (codec->cache_only) {
+               codec->cache_sync = 1;
+               return 0;
+       }
+
+       ret = codec->hw_write(codec->control_data, data, 2);
+       if (ret == 2)
+               return 0;
+       if (ret < 0)
+               return ret;
+       else
+               return -EIO;
+}
+
+#if defined(CONFIG_SPI_MASTER)
+static int snd_soc_4_12_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[1];
+       msg[1] = data[0];
+
+       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_4_12_spi_write NULL
+#endif
+
 static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
                                     unsigned int reg)
 {
@@ -38,6 +106,12 @@ static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
 
        if (reg < codec->reg_cache_size)
                cache[reg] = value;
+
+       if (codec->cache_only) {
+               codec->cache_sync = 1;
+               return 0;
+       }
+
        ret = codec->hw_write(codec->control_data, data, 2);
        if (ret == 2)
                return 0;
@@ -91,6 +165,11 @@ static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
        if (reg < codec->reg_cache_size)
                cache[reg] = value;
 
+       if (codec->cache_only) {
+               codec->cache_sync = 1;
+               return 0;
+       }
+
        if (codec->hw_write(codec->control_data, data, 2) == 2)
                return 0;
        else
@@ -119,6 +198,11 @@ static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
        if (!snd_soc_codec_volatile_register(codec, reg))
                reg_cache[reg] = value;
 
+       if (codec->cache_only) {
+               codec->cache_sync = 1;
+               return 0;
+       }
+
        if (codec->hw_write(codec->control_data, data, 3) == 3)
                return 0;
        else
@@ -131,10 +215,14 @@ static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
        u16 *cache = codec->reg_cache;
 
        if (reg >= codec->reg_cache_size ||
-           snd_soc_codec_volatile_register(codec, reg))
+           snd_soc_codec_volatile_register(codec, reg)) {
+               if (codec->cache_only)
+                       return -EINVAL;
+
                return codec->hw_read(codec, reg);
-       else
+       } else {
                return cache[reg];
+       }
 }
 
 #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
@@ -171,6 +259,114 @@ static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec,
 #define snd_soc_8_16_read_i2c NULL
 #endif
 
+#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
+static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec,
+                                         unsigned int r)
+{
+       struct i2c_msg xfer[2];
+       u16 reg = r;
+       u8 data;
+       int ret;
+       struct i2c_client *client = codec->control_data;
+
+       /* Write register */
+       xfer[0].addr = client->addr;
+       xfer[0].flags = 0;
+       xfer[0].len = 2;
+       xfer[0].buf = (u8 *)&reg;
+
+       /* Read data */
+       xfer[1].addr = client->addr;
+       xfer[1].flags = I2C_M_RD;
+       xfer[1].len = 1;
+       xfer[1].buf = &data;
+
+       ret = i2c_transfer(client->adapter, xfer, 2);
+       if (ret != 2) {
+               dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
+               return 0;
+       }
+
+       return data;
+}
+#else
+#define snd_soc_16_8_read_i2c NULL
+#endif
+
+static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec,
+                                    unsigned int reg)
+{
+       u16 *cache = codec->reg_cache;
+
+       reg &= 0xff;
+       if (reg >= codec->reg_cache_size)
+               return -1;
+       return cache[reg];
+}
+
+static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
+                            unsigned int value)
+{
+       u16 *cache = codec->reg_cache;
+       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 (codec->cache_only) {
+               codec->cache_sync = 1;
+               return 0;
+       }
+
+       ret = codec->hw_write(codec->control_data, data, 3);
+       if (ret == 3)
+               return 0;
+       if (ret < 0)
+               return ret;
+       else
+               return -EIO;
+}
+
+#if defined(CONFIG_SPI_MASTER)
+static int snd_soc_16_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[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_16_8_spi_write NULL
+#endif
+
+
 static struct {
        int addr_bits;
        int data_bits;
@@ -179,10 +375,15 @@ static struct {
        unsigned int (*read)(struct snd_soc_codec *, unsigned int);
        unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);
 } io_types[] = {
+       {
+               .addr_bits = 4, .data_bits = 12,
+               .write = snd_soc_4_12_write, .read = snd_soc_4_12_read,
+               .spi_write = snd_soc_4_12_spi_write,
+       },
        {
                .addr_bits = 7, .data_bits = 9,
                .write = snd_soc_7_9_write, .read = snd_soc_7_9_read,
-               .spi_write = snd_soc_7_9_spi_write 
+               .spi_write = snd_soc_7_9_spi_write,
        },
        {
                .addr_bits = 8, .data_bits = 8,
@@ -193,6 +394,12 @@ static struct {
                .write = snd_soc_8_16_write, .read = snd_soc_8_16_read,
                .i2c_read = snd_soc_8_16_read_i2c,
        },
+       {
+               .addr_bits = 16, .data_bits = 8,
+               .write = snd_soc_16_8_write, .read = snd_soc_16_8_read,
+               .i2c_read = snd_soc_16_8_read_i2c,
+               .spi_write = snd_soc_16_8_spi_write,
+       },
 };
 
 /**
index 0a6440c6f54a80a9af52aa10ffe9d898fe5c456d..a03bac943aafc8d3ef914f7c558999a1cbc0824d 100644 (file)
@@ -130,6 +130,29 @@ static ssize_t codec_reg_show(struct device *dev,
 
 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;
+
+       return sprintf(buf, "%ld\n", card->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;
+
+       strict_strtol(buf, 10, &card->pmdown_time);
+
+       return count;
+}
+
+static DEVICE_ATTR(pmdown_time, 0644, pmdown_time_show, pmdown_time_set);
+
 #ifdef CONFIG_DEBUG_FS
 static int codec_reg_open_file(struct inode *inode, struct file *file)
 {
@@ -542,7 +565,7 @@ static int soc_codec_close(struct snd_pcm_substream *substream)
                /* start delayed pop wq here for playback streams */
                codec_dai->pop_wait = 1;
                schedule_delayed_work(&card->delayed_work,
-                       msecs_to_jiffies(pmdown_time));
+                       msecs_to_jiffies(card->pmdown_time));
        } else {
                /* capture streams can be powered down now */
                snd_soc_dapm_stream_event(codec,
@@ -940,6 +963,12 @@ static int soc_resume(struct device *dev)
        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;
+
        /* 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
@@ -1039,6 +1068,8 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
        dev_dbg(card->dev, "All components present, instantiating\n");
 
        /* Found everything, bring it up */
+       card->pmdown_time = pmdown_time;
+
        if (card->probe) {
                ret = card->probe(pdev);
                if (ret < 0)
@@ -1122,6 +1153,10 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
        if (ret < 0)
                printk(KERN_WARNING "asoc: failed to add dapm sysfs entries\n");
 
+       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");
+
        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");
@@ -1276,8 +1311,8 @@ static int soc_new_pcm(struct snd_soc_device *socdev,
        codec_dai->codec = card->codec;
 
        /* check client and interface hw capabilities */
-       sprintf(new_name, "%s %s-%d", dai_link->stream_name, codec_dai->name,
-               num);
+       snprintf(new_name, sizeof(new_name), "%s %s-%d",
+                dai_link->stream_name, codec_dai->name, num);
 
        if (codec_dai->playback.channels_min)
                playback = 1;
@@ -1368,6 +1403,7 @@ 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;
        mutex_unlock(&codec->mutex);
        return 0;
 }
@@ -1427,9 +1463,9 @@ EXPORT_SYMBOL_GPL(snd_soc_update_bits);
  *
  * Returns 1 for change else 0.
  */
-static int snd_soc_update_bits_locked(struct snd_soc_codec *codec,
-                               unsigned short reg, unsigned int mask,
-                               unsigned int value)
+int snd_soc_update_bits_locked(struct snd_soc_codec *codec,
+                              unsigned short reg, unsigned int mask,
+                              unsigned int value)
 {
        int change;
 
@@ -1439,6 +1475,7 @@ static int snd_soc_update_bits_locked(struct snd_soc_codec *codec,
 
        return change;
 }
+EXPORT_SYMBOL_GPL(snd_soc_update_bits_locked);
 
 /**
  * snd_soc_test_bits - test register for change
index 0d294ef7259006e0681a9b1bb2092c608fde1925..6c3351095786f224448f62277d61aa583dfe000a 100644 (file)
 #include <sound/soc-dapm.h>
 #include <sound/initval.h>
 
-/* debug */
-#ifdef DEBUG
-#define dump_dapm(codec, action) dbg_dump_dapm(codec, action)
-#else
-#define dump_dapm(codec, action)
-#endif
-
 /* dapm power sequences - make this per codec in the future */
 static int dapm_up_seq[] = {
        [snd_soc_dapm_pre] = 0,
@@ -739,6 +732,8 @@ static int dapm_seq_compare(struct snd_soc_dapm_widget *a,
                            struct snd_soc_dapm_widget *b,
                            int sort[])
 {
+       if (a->codec != b->codec)
+               return (unsigned long)a - (unsigned long)b;
        if (sort[a->id] != sort[b->id])
                return sort[a->id] - sort[b->id];
        if (a->reg != b->reg)
@@ -1017,13 +1012,28 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
                        sys_power = 0;
                        break;
                case SND_SOC_DAPM_STREAM_NOP:
-                       sys_power = codec->bias_level != SND_SOC_BIAS_STANDBY;
+                       switch (codec->bias_level) {
+                               case SND_SOC_BIAS_STANDBY:
+                               case SND_SOC_BIAS_OFF:
+                                       sys_power = 0;
+                                       break;
+                               default:
+                                       sys_power = 1;
+                                       break;
+                       }
                        break;
                default:
                        break;
                }
        }
 
+       if (sys_power && codec->bias_level == SND_SOC_BIAS_OFF) {
+               ret = snd_soc_dapm_set_bias_level(socdev,
+                                                 SND_SOC_BIAS_STANDBY);
+               if (ret != 0)
+                       pr_err("Failed to turn on bias: %d\n", ret);
+       }
+
        /* 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)) {
@@ -1047,6 +1057,14 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
                        pr_err("Failed to apply standby bias: %d\n", ret);
        }
 
+       /* 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);
+               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,
@@ -1061,66 +1079,6 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
        return 0;
 }
 
-#ifdef DEBUG
-static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action)
-{
-       struct snd_soc_dapm_widget *w;
-       struct snd_soc_dapm_path *p = NULL;
-       int in, out;
-
-       printk("DAPM %s %s\n", codec->name, action);
-
-       list_for_each_entry(w, &codec->dapm_widgets, list) {
-
-               /* only display widgets that effect routing */
-               switch (w->id) {
-               case snd_soc_dapm_pre:
-               case snd_soc_dapm_post:
-               case snd_soc_dapm_vmid:
-                       continue;
-               case snd_soc_dapm_mux:
-               case snd_soc_dapm_value_mux:
-               case snd_soc_dapm_output:
-               case snd_soc_dapm_input:
-               case snd_soc_dapm_switch:
-               case snd_soc_dapm_hp:
-               case snd_soc_dapm_mic:
-               case snd_soc_dapm_spk:
-               case snd_soc_dapm_line:
-               case snd_soc_dapm_micbias:
-               case snd_soc_dapm_dac:
-               case snd_soc_dapm_adc:
-               case snd_soc_dapm_pga:
-               case snd_soc_dapm_mixer:
-               case snd_soc_dapm_mixer_named_ctl:
-               case snd_soc_dapm_supply:
-               case snd_soc_dapm_aif_in:
-               case snd_soc_dapm_aif_out:
-                       if (w->name) {
-                               in = is_connected_input_ep(w);
-                               dapm_clear_walk(w->codec);
-                               out = is_connected_output_ep(w);
-                               dapm_clear_walk(w->codec);
-                               printk("%s: %s  in %d out %d\n", w->name,
-                                       w->power ? "On":"Off",in, out);
-
-                               list_for_each_entry(p, &w->sources, list_sink) {
-                                       if (p->connect)
-                                               printk(" in  %s %s\n", p->name ? p->name : "static",
-                                                       p->source->name);
-                               }
-                               list_for_each_entry(p, &w->sinks, list_source) {
-                                       if (p->connect)
-                                               printk(" out %s %s\n", p->name ? p->name : "static",
-                                                       p->sink->name);
-                               }
-                       }
-               break;
-               }
-       }
-}
-#endif
-
 #ifdef CONFIG_DEBUG_FS
 static int dapm_widget_power_open_file(struct inode *inode, struct file *file)
 {
@@ -1147,9 +1105,16 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
        out = is_connected_output_ep(w);
        dapm_clear_walk(w->codec);
 
-       ret = snprintf(buf, PAGE_SIZE, "%s: %s  in %d out %d\n",
+       ret = snprintf(buf, PAGE_SIZE, "%s: %s  in %d out %d",
                       w->name, w->power ? "On" : "Off", in, out);
 
+       if (w->reg >= 0)
+               ret += snprintf(buf + ret, PAGE_SIZE - ret,
+                               " - R%d(0x%x) bit %d",
+                               w->reg, w->reg, w->shift);
+
+       ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
+
        if (w->sname)
                ret += snprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n",
                                w->sname,
@@ -1245,18 +1210,15 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
                        path->connect = 0; /* old connection must be powered down */
        }
 
-       if (found) {
+       if (found)
                dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP);
-               dump_dapm(widget->codec, "mux power update");
-       }
 
        return 0;
 }
 
 /* test and update the power status of a mixer or switch widget */
 static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
-                                  struct snd_kcontrol *kcontrol, int reg,
-                                  int val_mask, int val, int invert)
+                                  struct snd_kcontrol *kcontrol, int connect)
 {
        struct snd_soc_dapm_path *path;
        int found = 0;
@@ -1266,9 +1228,6 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
            widget->id != snd_soc_dapm_switch)
                return -ENODEV;
 
-       if (!snd_soc_test_bits(widget->codec, reg, val_mask, val))
-               return 0;
-
        /* find dapm widget path assoc with kcontrol */
        list_for_each_entry(path, &widget->codec->dapm_paths, list) {
                if (path->kcontrol != kcontrol)
@@ -1276,19 +1235,12 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
 
                /* found, now check type */
                found = 1;
-               if (val)
-                       /* new connection */
-                       path->connect = invert ? 0:1;
-               else
-                       /* old connection must be powered down */
-                       path->connect = invert ? 1:0;
+               path->connect = connect;
                break;
        }
 
-       if (found) {
+       if (found)
                dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP);
-               dump_dapm(widget->codec, "mixer power update");
-       }
 
        return 0;
 }
@@ -1404,9 +1356,7 @@ static int snd_soc_dapm_set_pin(struct snd_soc_codec *codec,
  */
 int snd_soc_dapm_sync(struct snd_soc_codec *codec)
 {
-       int ret = dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP);
-       dump_dapm(codec, "sync");
-       return ret;
+       return dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP);
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
 
@@ -1688,6 +1638,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
        unsigned int mask = (1 << fls(max)) - 1;
        unsigned int invert = mc->invert;
        unsigned int val, val2, val_mask;
+       int connect;
        int ret;
 
        val = (ucontrol->value.integer.value[0] & mask);
@@ -1714,7 +1665,17 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
                return 1;
        }
 
-       dapm_mixer_update_power(widget, kcontrol, reg, val_mask, val, invert);
+       if (snd_soc_test_bits(widget->codec, reg, val_mask, val)) {
+               if (val)
+                       /* new connection */
+                       connect = invert ? 0:1;
+               else
+                       /* old connection must be powered down */
+                       connect = invert ? 1:0;
+
+               dapm_mixer_update_power(widget, kcontrol, connect);
+       }
+
        if (widget->event) {
                if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
                        ret = widget->event(widget, kcontrol,
@@ -2152,7 +2113,6 @@ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec,
 
        dapm_power_widgets(codec, event);
        mutex_unlock(&codec->mutex);
-       dump_dapm(codec, __func__);
        return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event);
index 73525c048e7f60d7613eef093f850c6d204215e4..8c2925814ce46fba77978ab697f54a284f99510d 100644 (file)
@@ -21,6 +21,18 @@ config SND_USB_AUDIO
          To compile this driver as a module, choose M here: the module
          will be called snd-usb-audio.
 
+config SND_USB_UA101
+       tristate "Edirol UA-101 driver (EXPERIMENTAL)"
+       depends on EXPERIMENTAL
+       select SND_PCM
+       select SND_RAWMIDI
+       help
+         Say Y here to include support for the Edirol UA-101 audio/MIDI
+         interface.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-ua101.
+
 config SND_USB_USX2Y
        tristate "Tascam US-122, US-224 and US-428 USB driver"
        depends on X86 || PPC || ALPHA
index abb288bfe35db2a721bb1d512275bbac03e7f145..5bf64aef95581f813894dc5dc00b40c658288e17 100644 (file)
@@ -4,9 +4,11 @@
 
 snd-usb-audio-objs := usbaudio.o usbmixer.o
 snd-usb-lib-objs := usbmidi.o
+snd-ua101-objs := ua101.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_USB_AUDIO) += snd-usb-audio.o snd-usb-lib.o
+obj-$(CONFIG_SND_USB_UA101) += snd-ua101.o snd-usb-lib.o
 obj-$(CONFIG_SND_USB_USX2Y) += snd-usb-lib.o
 obj-$(CONFIG_SND_USB_US122L) += snd-usb-lib.o
 
diff --git a/sound/usb/ua101.c b/sound/usb/ua101.c
new file mode 100644 (file)
index 0000000..4f4ccdf
--- /dev/null
@@ -0,0 +1,1421 @@
+/*
+ * Edirol UA-101 driver
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ *
+ * This driver is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2.
+ *
+ * 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 driver.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/usb/audio.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include "usbaudio.h"
+
+MODULE_DESCRIPTION("Edirol UA-101 driver");
+MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_SUPPORTED_DEVICE("{{Edirol,UA-101}}");
+
+/* I use my UA-1A for testing because I don't have a UA-101 ... */
+#define UA1A_HACK
+
+/*
+ * Should not be lower than the minimum scheduling delay of the host
+ * controller.  Some Intel controllers need more than one frame; as long as
+ * that driver doesn't tell us about this, use 1.5 frames just to be sure.
+ */
+#define MIN_QUEUE_LENGTH       12
+/* Somewhat random. */
+#define MAX_QUEUE_LENGTH       30
+/*
+ * This magic value optimizes memory usage efficiency for the UA-101's packet
+ * sizes at all sample rates, taking into account the stupid cache pool sizes
+ * that usb_buffer_alloc() uses.
+ */
+#define DEFAULT_QUEUE_LENGTH   21
+
+#define MAX_PACKET_SIZE                672 /* hardware specific */
+#define MAX_MEMORY_BUFFERS     DIV_ROUND_UP(MAX_QUEUE_LENGTH, \
+                                            PAGE_SIZE / MAX_PACKET_SIZE)
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+static unsigned int queue_length = 21;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "card index");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "enable card");
+module_param(queue_length, uint, 0644);
+MODULE_PARM_DESC(queue_length, "USB queue length in microframes, "
+                __stringify(MIN_QUEUE_LENGTH)"-"__stringify(MAX_QUEUE_LENGTH));
+
+enum {
+       INTF_PLAYBACK,
+       INTF_CAPTURE,
+       INTF_MIDI,
+
+       INTF_COUNT
+};
+
+/* bits in struct ua101::states */
+enum {
+       USB_CAPTURE_RUNNING,
+       USB_PLAYBACK_RUNNING,
+       ALSA_CAPTURE_OPEN,
+       ALSA_PLAYBACK_OPEN,
+       ALSA_CAPTURE_RUNNING,
+       ALSA_PLAYBACK_RUNNING,
+       CAPTURE_URB_COMPLETED,
+       PLAYBACK_URB_COMPLETED,
+       DISCONNECTED,
+};
+
+struct ua101 {
+       struct usb_device *dev;
+       struct snd_card *card;
+       struct usb_interface *intf[INTF_COUNT];
+       int card_index;
+       struct snd_pcm *pcm;
+       struct list_head midi_list;
+       u64 format_bit;
+       unsigned int rate;
+       unsigned int packets_per_second;
+       spinlock_t lock;
+       struct mutex mutex;
+       unsigned long states;
+
+       /* FIFO to synchronize playback rate to capture rate */
+       unsigned int rate_feedback_start;
+       unsigned int rate_feedback_count;
+       u8 rate_feedback[MAX_QUEUE_LENGTH];
+
+       struct list_head ready_playback_urbs;
+       struct tasklet_struct playback_tasklet;
+       wait_queue_head_t alsa_capture_wait;
+       wait_queue_head_t rate_feedback_wait;
+       wait_queue_head_t alsa_playback_wait;
+       struct ua101_stream {
+               struct snd_pcm_substream *substream;
+               unsigned int usb_pipe;
+               unsigned int channels;
+               unsigned int frame_bytes;
+               unsigned int max_packet_bytes;
+               unsigned int period_pos;
+               unsigned int buffer_pos;
+               unsigned int queue_length;
+               struct ua101_urb {
+                       struct urb urb;
+                       struct usb_iso_packet_descriptor iso_frame_desc[1];
+                       struct list_head ready_list;
+               } *urbs[MAX_QUEUE_LENGTH];
+               struct {
+                       unsigned int size;
+                       void *addr;
+                       dma_addr_t dma;
+               } buffers[MAX_MEMORY_BUFFERS];
+       } capture, playback;
+
+       unsigned int fps[10];
+       unsigned int frame_counter;
+};
+
+static DEFINE_MUTEX(devices_mutex);
+static unsigned int devices_used;
+static struct usb_driver ua101_driver;
+
+static void abort_alsa_playback(struct ua101 *ua);
+static void abort_alsa_capture(struct ua101 *ua);
+
+static const char *usb_error_string(int err)
+{
+       switch (err) {
+       case -ENODEV:
+               return "no device";
+       case -ENOENT:
+               return "endpoint not enabled";
+       case -EPIPE:
+               return "endpoint stalled";
+       case -ENOSPC:
+               return "not enough bandwidth";
+       case -ESHUTDOWN:
+               return "device disabled";
+       case -EHOSTUNREACH:
+               return "device suspended";
+       case -EINVAL:
+       case -EAGAIN:
+       case -EFBIG:
+       case -EMSGSIZE:
+               return "internal error";
+       default:
+               return "unknown error";
+       }
+}
+
+static void abort_usb_capture(struct ua101 *ua)
+{
+       if (test_and_clear_bit(USB_CAPTURE_RUNNING, &ua->states)) {
+               wake_up(&ua->alsa_capture_wait);
+               wake_up(&ua->rate_feedback_wait);
+       }
+}
+
+static void abort_usb_playback(struct ua101 *ua)
+{
+       if (test_and_clear_bit(USB_PLAYBACK_RUNNING, &ua->states))
+               wake_up(&ua->alsa_playback_wait);
+}
+
+static void playback_urb_complete(struct urb *usb_urb)
+{
+       struct ua101_urb *urb = (struct ua101_urb *)usb_urb;
+       struct ua101 *ua = urb->urb.context;
+       unsigned long flags;
+
+       if (unlikely(urb->urb.status == -ENOENT ||      /* unlinked */
+                    urb->urb.status == -ENODEV ||      /* device removed */
+                    urb->urb.status == -ECONNRESET ||  /* unlinked */
+                    urb->urb.status == -ESHUTDOWN)) {  /* device disabled */
+               abort_usb_playback(ua);
+               abort_alsa_playback(ua);
+               return;
+       }
+
+       if (test_bit(USB_PLAYBACK_RUNNING, &ua->states)) {
+               /* append URB to FIFO */
+               spin_lock_irqsave(&ua->lock, flags);
+               list_add_tail(&urb->ready_list, &ua->ready_playback_urbs);
+               if (ua->rate_feedback_count > 0)
+                       tasklet_schedule(&ua->playback_tasklet);
+               ua->playback.substream->runtime->delay -=
+                               urb->urb.iso_frame_desc[0].length /
+                                               ua->playback.frame_bytes;
+               spin_unlock_irqrestore(&ua->lock, flags);
+       }
+}
+
+static void first_playback_urb_complete(struct urb *urb)
+{
+       struct ua101 *ua = urb->context;
+
+       urb->complete = playback_urb_complete;
+       playback_urb_complete(urb);
+
+       set_bit(PLAYBACK_URB_COMPLETED, &ua->states);
+       wake_up(&ua->alsa_playback_wait);
+}
+
+/* copy data from the ALSA ring buffer into the URB buffer */
+static bool copy_playback_data(struct ua101_stream *stream, struct urb *urb,
+                              unsigned int frames)
+{
+       struct snd_pcm_runtime *runtime;
+       unsigned int frame_bytes, frames1;
+       const u8 *source;
+
+       runtime = stream->substream->runtime;
+       frame_bytes = stream->frame_bytes;
+       source = runtime->dma_area + stream->buffer_pos * frame_bytes;
+       if (stream->buffer_pos + frames <= runtime->buffer_size) {
+               memcpy(urb->transfer_buffer, source, frames * frame_bytes);
+       } else {
+               /* wrap around at end of ring buffer */
+               frames1 = runtime->buffer_size - stream->buffer_pos;
+               memcpy(urb->transfer_buffer, source, frames1 * frame_bytes);
+               memcpy(urb->transfer_buffer + frames1 * frame_bytes,
+                      runtime->dma_area, (frames - frames1) * frame_bytes);
+       }
+
+       stream->buffer_pos += frames;
+       if (stream->buffer_pos >= runtime->buffer_size)
+               stream->buffer_pos -= runtime->buffer_size;
+       stream->period_pos += frames;
+       if (stream->period_pos >= runtime->period_size) {
+               stream->period_pos -= runtime->period_size;
+               return true;
+       }
+       return false;
+}
+
+static inline void add_with_wraparound(struct ua101 *ua,
+                                      unsigned int *value, unsigned int add)
+{
+       *value += add;
+       if (*value >= ua->playback.queue_length)
+               *value -= ua->playback.queue_length;
+}
+
+static void playback_tasklet(unsigned long data)
+{
+       struct ua101 *ua = (void *)data;
+       unsigned long flags;
+       unsigned int frames;
+       struct ua101_urb *urb;
+       bool do_period_elapsed = false;
+       int err;
+
+       if (unlikely(!test_bit(USB_PLAYBACK_RUNNING, &ua->states)))
+               return;
+
+       /*
+        * Synchronizing the playback rate to the capture rate is done by using
+        * the same sequence of packet sizes for both streams.
+        * Submitting a playback URB therefore requires both a ready URB and
+        * the size of the corresponding capture packet, i.e., both playback
+        * and capture URBs must have been completed.  Since the USB core does
+        * not guarantee that playback and capture complete callbacks are
+        * called alternately, we use two FIFOs for packet sizes and read URBs;
+        * submitting playback URBs is possible as long as both FIFOs are
+        * nonempty.
+        */
+       spin_lock_irqsave(&ua->lock, flags);
+       while (ua->rate_feedback_count > 0 &&
+              !list_empty(&ua->ready_playback_urbs)) {
+               /* take packet size out of FIFO */
+               frames = ua->rate_feedback[ua->rate_feedback_start];
+               add_with_wraparound(ua, &ua->rate_feedback_start, 1);
+               ua->rate_feedback_count--;
+
+               /* take URB out of FIFO */
+               urb = list_first_entry(&ua->ready_playback_urbs,
+                                      struct ua101_urb, ready_list);
+               list_del(&urb->ready_list);
+
+               /* fill packet with data or silence */
+               urb->urb.iso_frame_desc[0].length =
+                       frames * ua->playback.frame_bytes;
+               if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states))
+                       do_period_elapsed |= copy_playback_data(&ua->playback,
+                                                               &urb->urb,
+                                                               frames);
+               else
+                       memset(urb->urb.transfer_buffer, 0,
+                              urb->urb.iso_frame_desc[0].length);
+
+               /* and off you go ... */
+               err = usb_submit_urb(&urb->urb, GFP_ATOMIC);
+               if (unlikely(err < 0)) {
+                       spin_unlock_irqrestore(&ua->lock, flags);
+                       abort_usb_playback(ua);
+                       abort_alsa_playback(ua);
+                       dev_err(&ua->dev->dev, "USB request error %d: %s\n",
+                               err, usb_error_string(err));
+                       return;
+               }
+               ua->playback.substream->runtime->delay += frames;
+       }
+       spin_unlock_irqrestore(&ua->lock, flags);
+       if (do_period_elapsed)
+               snd_pcm_period_elapsed(ua->playback.substream);
+}
+
+/* copy data from the URB buffer into the ALSA ring buffer */
+static bool copy_capture_data(struct ua101_stream *stream, struct urb *urb,
+                             unsigned int frames)
+{
+       struct snd_pcm_runtime *runtime;
+       unsigned int frame_bytes, frames1;
+       u8 *dest;
+
+       runtime = stream->substream->runtime;
+       frame_bytes = stream->frame_bytes;
+       dest = runtime->dma_area + stream->buffer_pos * frame_bytes;
+       if (stream->buffer_pos + frames <= runtime->buffer_size) {
+               memcpy(dest, urb->transfer_buffer, frames * frame_bytes);
+       } else {
+               /* wrap around at end of ring buffer */
+               frames1 = runtime->buffer_size - stream->buffer_pos;
+               memcpy(dest, urb->transfer_buffer, frames1 * frame_bytes);
+               memcpy(runtime->dma_area,
+                      urb->transfer_buffer + frames1 * frame_bytes,
+                      (frames - frames1) * frame_bytes);
+       }
+
+       stream->buffer_pos += frames;
+       if (stream->buffer_pos >= runtime->buffer_size)
+               stream->buffer_pos -= runtime->buffer_size;
+       stream->period_pos += frames;
+       if (stream->period_pos >= runtime->period_size) {
+               stream->period_pos -= runtime->period_size;
+               return true;
+       }
+       return false;
+}
+
+static void capture_urb_complete(struct urb *urb)
+{
+       struct ua101 *ua = urb->context;
+       struct ua101_stream *stream = &ua->capture;
+       unsigned long flags;
+       unsigned int frames, write_ptr;
+       bool do_period_elapsed;
+       int err;
+
+       if (unlikely(urb->status == -ENOENT ||          /* unlinked */
+                    urb->status == -ENODEV ||          /* device removed */
+                    urb->status == -ECONNRESET ||      /* unlinked */
+                    urb->status == -ESHUTDOWN))        /* device disabled */
+               goto stream_stopped;
+
+       if (urb->status >= 0 && urb->iso_frame_desc[0].status >= 0)
+               frames = urb->iso_frame_desc[0].actual_length /
+                       stream->frame_bytes;
+       else
+               frames = 0;
+
+       spin_lock_irqsave(&ua->lock, flags);
+
+       if (frames > 0 && test_bit(ALSA_CAPTURE_RUNNING, &ua->states))
+               do_period_elapsed = copy_capture_data(stream, urb, frames);
+       else
+               do_period_elapsed = false;
+
+       if (test_bit(USB_CAPTURE_RUNNING, &ua->states)) {
+               err = usb_submit_urb(urb, GFP_ATOMIC);
+               if (unlikely(err < 0)) {
+                       spin_unlock_irqrestore(&ua->lock, flags);
+                       dev_err(&ua->dev->dev, "USB request error %d: %s\n",
+                               err, usb_error_string(err));
+                       goto stream_stopped;
+               }
+
+               /* append packet size to FIFO */
+               write_ptr = ua->rate_feedback_start;
+               add_with_wraparound(ua, &write_ptr, ua->rate_feedback_count);
+               ua->rate_feedback[write_ptr] = frames;
+               if (ua->rate_feedback_count < ua->playback.queue_length) {
+                       ua->rate_feedback_count++;
+                       if (ua->rate_feedback_count ==
+                                               ua->playback.queue_length)
+                               wake_up(&ua->rate_feedback_wait);
+               } else {
+                       /*
+                        * Ring buffer overflow; this happens when the playback
+                        * stream is not running.  Throw away the oldest entry,
+                        * so that the playback stream, when it starts, sees
+                        * the most recent packet sizes.
+                        */
+                       add_with_wraparound(ua, &ua->rate_feedback_start, 1);
+               }
+               if (test_bit(USB_PLAYBACK_RUNNING, &ua->states) &&
+                   !list_empty(&ua->ready_playback_urbs))
+                       tasklet_schedule(&ua->playback_tasklet);
+       }
+
+       spin_unlock_irqrestore(&ua->lock, flags);
+
+       if (do_period_elapsed)
+               snd_pcm_period_elapsed(stream->substream);
+
+       /* for debugging: measure the sample rate relative to the USB clock */
+       ua->fps[ua->frame_counter++ / ua->packets_per_second] += frames;
+       if (ua->frame_counter >= ARRAY_SIZE(ua->fps) * ua->packets_per_second) {
+               printk(KERN_DEBUG "capture rate:");
+               for (frames = 0; frames < ARRAY_SIZE(ua->fps); ++frames)
+                       printk(KERN_CONT " %u", ua->fps[frames]);
+               printk(KERN_CONT "\n");
+               memset(ua->fps, 0, sizeof(ua->fps));
+               ua->frame_counter = 0;
+       }
+       return;
+
+stream_stopped:
+       abort_usb_playback(ua);
+       abort_usb_capture(ua);
+       abort_alsa_playback(ua);
+       abort_alsa_capture(ua);
+}
+
+static void first_capture_urb_complete(struct urb *urb)
+{
+       struct ua101 *ua = urb->context;
+
+       urb->complete = capture_urb_complete;
+       capture_urb_complete(urb);
+
+       set_bit(CAPTURE_URB_COMPLETED, &ua->states);
+       wake_up(&ua->alsa_capture_wait);
+}
+
+static int submit_stream_urbs(struct ua101 *ua, struct ua101_stream *stream)
+{
+       unsigned int i;
+
+       for (i = 0; i < stream->queue_length; ++i) {
+               int err = usb_submit_urb(&stream->urbs[i]->urb, GFP_KERNEL);
+               if (err < 0) {
+                       dev_err(&ua->dev->dev, "USB request error %d: %s\n",
+                               err, usb_error_string(err));
+                       return err;
+               }
+       }
+       return 0;
+}
+
+static void kill_stream_urbs(struct ua101_stream *stream)
+{
+       unsigned int i;
+
+       for (i = 0; i < stream->queue_length; ++i)
+               usb_kill_urb(&stream->urbs[i]->urb);
+}
+
+static int enable_iso_interface(struct ua101 *ua, unsigned int intf_index)
+{
+       struct usb_host_interface *alts;
+
+       alts = ua->intf[intf_index]->cur_altsetting;
+       if (alts->desc.bAlternateSetting != 1) {
+               int err = usb_set_interface(ua->dev,
+                                           alts->desc.bInterfaceNumber, 1);
+               if (err < 0) {
+                       dev_err(&ua->dev->dev,
+                               "cannot initialize interface; error %d: %s\n",
+                               err, usb_error_string(err));
+                       return err;
+               }
+       }
+       return 0;
+}
+
+static void disable_iso_interface(struct ua101 *ua, unsigned int intf_index)
+{
+       struct usb_host_interface *alts;
+
+       alts = ua->intf[intf_index]->cur_altsetting;
+       if (alts->desc.bAlternateSetting != 0) {
+               int err = usb_set_interface(ua->dev,
+                                           alts->desc.bInterfaceNumber, 0);
+               if (err < 0 && !test_bit(DISCONNECTED, &ua->states))
+                       dev_warn(&ua->dev->dev,
+                                "interface reset failed; error %d: %s\n",
+                                err, usb_error_string(err));
+       }
+}
+
+static void stop_usb_capture(struct ua101 *ua)
+{
+       clear_bit(USB_CAPTURE_RUNNING, &ua->states);
+
+       kill_stream_urbs(&ua->capture);
+
+       disable_iso_interface(ua, INTF_CAPTURE);
+}
+
+static int start_usb_capture(struct ua101 *ua)
+{
+       int err;
+
+       if (test_bit(DISCONNECTED, &ua->states))
+               return -ENODEV;
+
+       if (test_bit(USB_CAPTURE_RUNNING, &ua->states))
+               return 0;
+
+       kill_stream_urbs(&ua->capture);
+
+       err = enable_iso_interface(ua, INTF_CAPTURE);
+       if (err < 0)
+               return err;
+
+       clear_bit(CAPTURE_URB_COMPLETED, &ua->states);
+       ua->capture.urbs[0]->urb.complete = first_capture_urb_complete;
+       ua->rate_feedback_start = 0;
+       ua->rate_feedback_count = 0;
+
+       set_bit(USB_CAPTURE_RUNNING, &ua->states);
+       err = submit_stream_urbs(ua, &ua->capture);
+       if (err < 0)
+               stop_usb_capture(ua);
+       return err;
+}
+
+static void stop_usb_playback(struct ua101 *ua)
+{
+       clear_bit(USB_PLAYBACK_RUNNING, &ua->states);
+
+       kill_stream_urbs(&ua->playback);
+
+       tasklet_kill(&ua->playback_tasklet);
+
+       disable_iso_interface(ua, INTF_PLAYBACK);
+}
+
+static int start_usb_playback(struct ua101 *ua)
+{
+       unsigned int i, frames;
+       struct urb *urb;
+       int err = 0;
+
+       if (test_bit(DISCONNECTED, &ua->states))
+               return -ENODEV;
+
+       if (test_bit(USB_PLAYBACK_RUNNING, &ua->states))
+               return 0;
+
+       kill_stream_urbs(&ua->playback);
+       tasklet_kill(&ua->playback_tasklet);
+
+       err = enable_iso_interface(ua, INTF_PLAYBACK);
+       if (err < 0)
+               return err;
+
+       clear_bit(PLAYBACK_URB_COMPLETED, &ua->states);
+       ua->playback.urbs[0]->urb.complete =
+               first_playback_urb_complete;
+       spin_lock_irq(&ua->lock);
+       INIT_LIST_HEAD(&ua->ready_playback_urbs);
+       spin_unlock_irq(&ua->lock);
+
+       /*
+        * We submit the initial URBs all at once, so we have to wait for the
+        * packet size FIFO to be full.
+        */
+       wait_event(ua->rate_feedback_wait,
+                  ua->rate_feedback_count >= ua->playback.queue_length ||
+                  !test_bit(USB_CAPTURE_RUNNING, &ua->states) ||
+                  test_bit(DISCONNECTED, &ua->states));
+       if (test_bit(DISCONNECTED, &ua->states)) {
+               stop_usb_playback(ua);
+               return -ENODEV;
+       }
+       if (!test_bit(USB_CAPTURE_RUNNING, &ua->states)) {
+               stop_usb_playback(ua);
+               return -EIO;
+       }
+
+       for (i = 0; i < ua->playback.queue_length; ++i) {
+               /* all initial URBs contain silence */
+               spin_lock_irq(&ua->lock);
+               frames = ua->rate_feedback[ua->rate_feedback_start];
+               add_with_wraparound(ua, &ua->rate_feedback_start, 1);
+               ua->rate_feedback_count--;
+               spin_unlock_irq(&ua->lock);
+               urb = &ua->playback.urbs[i]->urb;
+               urb->iso_frame_desc[0].length =
+                       frames * ua->playback.frame_bytes;
+               memset(urb->transfer_buffer, 0,
+                      urb->iso_frame_desc[0].length);
+       }
+
+       set_bit(USB_PLAYBACK_RUNNING, &ua->states);
+       err = submit_stream_urbs(ua, &ua->playback);
+       if (err < 0)
+               stop_usb_playback(ua);
+       return err;
+}
+
+static void abort_alsa_capture(struct ua101 *ua)
+{
+       if (test_bit(ALSA_CAPTURE_RUNNING, &ua->states))
+               snd_pcm_stop(ua->capture.substream, SNDRV_PCM_STATE_XRUN);
+}
+
+static void abort_alsa_playback(struct ua101 *ua)
+{
+       if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states))
+               snd_pcm_stop(ua->playback.substream, SNDRV_PCM_STATE_XRUN);
+}
+
+static int set_stream_hw(struct ua101 *ua, struct snd_pcm_substream *substream,
+                        unsigned int channels)
+{
+       int err;
+
+       substream->runtime->hw.info =
+               SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_MMAP_VALID |
+               SNDRV_PCM_INFO_BATCH |
+               SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_FIFO_IN_FRAMES;
+       substream->runtime->hw.formats = ua->format_bit;
+       substream->runtime->hw.rates = snd_pcm_rate_to_rate_bit(ua->rate);
+       substream->runtime->hw.rate_min = ua->rate;
+       substream->runtime->hw.rate_max = ua->rate;
+       substream->runtime->hw.channels_min = channels;
+       substream->runtime->hw.channels_max = channels;
+       substream->runtime->hw.buffer_bytes_max = 45000 * 1024;
+       substream->runtime->hw.period_bytes_min = 1;
+       substream->runtime->hw.period_bytes_max = UINT_MAX;
+       substream->runtime->hw.periods_min = 2;
+       substream->runtime->hw.periods_max = UINT_MAX;
+       err = snd_pcm_hw_constraint_minmax(substream->runtime,
+                                          SNDRV_PCM_HW_PARAM_PERIOD_TIME,
+                                          1500000 / ua->packets_per_second,
+                                          8192000);
+       if (err < 0)
+               return err;
+       err = snd_pcm_hw_constraint_msbits(substream->runtime, 0, 32, 24);
+       return err;
+}
+
+static int capture_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct ua101 *ua = substream->private_data;
+       int err;
+
+       ua->capture.substream = substream;
+       err = set_stream_hw(ua, substream, ua->capture.channels);
+       if (err < 0)
+               return err;
+       substream->runtime->hw.fifo_size =
+               DIV_ROUND_CLOSEST(ua->rate, ua->packets_per_second);
+       substream->runtime->delay = substream->runtime->hw.fifo_size;
+
+       mutex_lock(&ua->mutex);
+       err = start_usb_capture(ua);
+       if (err >= 0)
+               set_bit(ALSA_CAPTURE_OPEN, &ua->states);
+       mutex_unlock(&ua->mutex);
+       return err;
+}
+
+static int playback_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct ua101 *ua = substream->private_data;
+       int err;
+
+       ua->playback.substream = substream;
+       err = set_stream_hw(ua, substream, ua->playback.channels);
+       if (err < 0)
+               return err;
+       substream->runtime->hw.fifo_size =
+               DIV_ROUND_CLOSEST(ua->rate * ua->playback.queue_length,
+                                 ua->packets_per_second);
+
+       mutex_lock(&ua->mutex);
+       err = start_usb_capture(ua);
+       if (err < 0)
+               goto error;
+       err = start_usb_playback(ua);
+       if (err < 0) {
+               if (!test_bit(ALSA_CAPTURE_OPEN, &ua->states))
+                       stop_usb_capture(ua);
+               goto error;
+       }
+       set_bit(ALSA_PLAYBACK_OPEN, &ua->states);
+error:
+       mutex_unlock(&ua->mutex);
+       return err;
+}
+
+static int capture_pcm_close(struct snd_pcm_substream *substream)
+{
+       struct ua101 *ua = substream->private_data;
+
+       mutex_lock(&ua->mutex);
+       clear_bit(ALSA_CAPTURE_OPEN, &ua->states);
+       if (!test_bit(ALSA_PLAYBACK_OPEN, &ua->states))
+               stop_usb_capture(ua);
+       mutex_unlock(&ua->mutex);
+       return 0;
+}
+
+static int playback_pcm_close(struct snd_pcm_substream *substream)
+{
+       struct ua101 *ua = substream->private_data;
+
+       mutex_lock(&ua->mutex);
+       stop_usb_playback(ua);
+       clear_bit(ALSA_PLAYBACK_OPEN, &ua->states);
+       if (!test_bit(ALSA_CAPTURE_OPEN, &ua->states))
+               stop_usb_capture(ua);
+       mutex_unlock(&ua->mutex);
+       return 0;
+}
+
+static int capture_pcm_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *hw_params)
+{
+       struct ua101 *ua = substream->private_data;
+       int err;
+
+       mutex_lock(&ua->mutex);
+       err = start_usb_capture(ua);
+       mutex_unlock(&ua->mutex);
+       if (err < 0)
+               return err;
+
+       return snd_pcm_lib_alloc_vmalloc_buffer(substream,
+                                               params_buffer_bytes(hw_params));
+}
+
+static int playback_pcm_hw_params(struct snd_pcm_substream *substream,
+                                 struct snd_pcm_hw_params *hw_params)
+{
+       struct ua101 *ua = substream->private_data;
+       int err;
+
+       mutex_lock(&ua->mutex);
+       err = start_usb_capture(ua);
+       if (err >= 0)
+               err = start_usb_playback(ua);
+       mutex_unlock(&ua->mutex);
+       if (err < 0)
+               return err;
+
+       return snd_pcm_lib_alloc_vmalloc_buffer(substream,
+                                               params_buffer_bytes(hw_params));
+}
+
+static int ua101_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static int capture_pcm_prepare(struct snd_pcm_substream *substream)
+{
+       struct ua101 *ua = substream->private_data;
+       int err;
+
+       mutex_lock(&ua->mutex);
+       err = start_usb_capture(ua);
+       mutex_unlock(&ua->mutex);
+       if (err < 0)
+               return err;
+
+       /*
+        * The EHCI driver schedules the first packet of an iso stream at 10 ms
+        * in the future, i.e., no data is actually captured for that long.
+        * Take the wait here so that the stream is known to be actually
+        * running when the start trigger has been called.
+        */
+       wait_event(ua->alsa_capture_wait,
+                  test_bit(CAPTURE_URB_COMPLETED, &ua->states) ||
+                  !test_bit(USB_CAPTURE_RUNNING, &ua->states));
+       if (test_bit(DISCONNECTED, &ua->states))
+               return -ENODEV;
+       if (!test_bit(USB_CAPTURE_RUNNING, &ua->states))
+               return -EIO;
+
+       ua->capture.period_pos = 0;
+       ua->capture.buffer_pos = 0;
+       return 0;
+}
+
+static int playback_pcm_prepare(struct snd_pcm_substream *substream)
+{
+       struct ua101 *ua = substream->private_data;
+       int err;
+
+       mutex_lock(&ua->mutex);
+       err = start_usb_capture(ua);
+       if (err >= 0)
+               err = start_usb_playback(ua);
+       mutex_unlock(&ua->mutex);
+       if (err < 0)
+               return err;
+
+       /* see the comment in capture_pcm_prepare() */
+       wait_event(ua->alsa_playback_wait,
+                  test_bit(PLAYBACK_URB_COMPLETED, &ua->states) ||
+                  !test_bit(USB_PLAYBACK_RUNNING, &ua->states));
+       if (test_bit(DISCONNECTED, &ua->states))
+               return -ENODEV;
+       if (!test_bit(USB_PLAYBACK_RUNNING, &ua->states))
+               return -EIO;
+
+       substream->runtime->delay = 0;
+       ua->playback.period_pos = 0;
+       ua->playback.buffer_pos = 0;
+       return 0;
+}
+
+static int capture_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct ua101 *ua = substream->private_data;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               if (!test_bit(USB_CAPTURE_RUNNING, &ua->states))
+                       return -EIO;
+               set_bit(ALSA_CAPTURE_RUNNING, &ua->states);
+               return 0;
+       case SNDRV_PCM_TRIGGER_STOP:
+               clear_bit(ALSA_CAPTURE_RUNNING, &ua->states);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int playback_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct ua101 *ua = substream->private_data;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               if (!test_bit(USB_PLAYBACK_RUNNING, &ua->states))
+                       return -EIO;
+               set_bit(ALSA_PLAYBACK_RUNNING, &ua->states);
+               return 0;
+       case SNDRV_PCM_TRIGGER_STOP:
+               clear_bit(ALSA_PLAYBACK_RUNNING, &ua->states);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static inline snd_pcm_uframes_t ua101_pcm_pointer(struct ua101 *ua,
+                                                 struct ua101_stream *stream)
+{
+       unsigned long flags;
+       unsigned int pos;
+
+       spin_lock_irqsave(&ua->lock, flags);
+       pos = stream->buffer_pos;
+       spin_unlock_irqrestore(&ua->lock, flags);
+       return pos;
+}
+
+static snd_pcm_uframes_t capture_pcm_pointer(struct snd_pcm_substream *subs)
+{
+       struct ua101 *ua = subs->private_data;
+
+       return ua101_pcm_pointer(ua, &ua->capture);
+}
+
+static snd_pcm_uframes_t playback_pcm_pointer(struct snd_pcm_substream *subs)
+{
+       struct ua101 *ua = subs->private_data;
+
+       return ua101_pcm_pointer(ua, &ua->playback);
+}
+
+static struct snd_pcm_ops capture_pcm_ops = {
+       .open = capture_pcm_open,
+       .close = capture_pcm_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = capture_pcm_hw_params,
+       .hw_free = ua101_pcm_hw_free,
+       .prepare = capture_pcm_prepare,
+       .trigger = capture_pcm_trigger,
+       .pointer = capture_pcm_pointer,
+       .page = snd_pcm_lib_get_vmalloc_page,
+       .mmap = snd_pcm_lib_mmap_vmalloc,
+};
+
+static struct snd_pcm_ops playback_pcm_ops = {
+       .open = playback_pcm_open,
+       .close = playback_pcm_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = playback_pcm_hw_params,
+       .hw_free = ua101_pcm_hw_free,
+       .prepare = playback_pcm_prepare,
+       .trigger = playback_pcm_trigger,
+       .pointer = playback_pcm_pointer,
+       .page = snd_pcm_lib_get_vmalloc_page,
+       .mmap = snd_pcm_lib_mmap_vmalloc,
+};
+
+static const struct uac_format_type_i_discrete_descriptor *
+find_format_descriptor(struct usb_interface *interface)
+{
+       struct usb_host_interface *alt;
+       u8 *extra;
+       int extralen;
+
+       if (interface->num_altsetting != 2) {
+               dev_err(&interface->dev, "invalid num_altsetting\n");
+               return NULL;
+       }
+
+       alt = &interface->altsetting[0];
+       if (alt->desc.bNumEndpoints != 0) {
+               dev_err(&interface->dev, "invalid bNumEndpoints\n");
+               return NULL;
+       }
+
+       alt = &interface->altsetting[1];
+       if (alt->desc.bNumEndpoints != 1) {
+               dev_err(&interface->dev, "invalid bNumEndpoints\n");
+               return NULL;
+       }
+
+       extra = alt->extra;
+       extralen = alt->extralen;
+       while (extralen >= sizeof(struct usb_descriptor_header)) {
+               struct uac_format_type_i_discrete_descriptor *desc;
+
+               desc = (struct uac_format_type_i_discrete_descriptor *)extra;
+               if (desc->bLength > extralen) {
+                       dev_err(&interface->dev, "descriptor overflow\n");
+                       return NULL;
+               }
+               if (desc->bLength == UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1) &&
+                   desc->bDescriptorType == USB_DT_CS_INTERFACE &&
+                   desc->bDescriptorSubtype == UAC_FORMAT_TYPE) {
+                       if (desc->bFormatType != UAC_FORMAT_TYPE_I_PCM ||
+                           desc->bSamFreqType != 1) {
+                               dev_err(&interface->dev,
+                                       "invalid format type\n");
+                               return NULL;
+                       }
+                       return desc;
+               }
+               extralen -= desc->bLength;
+               extra += desc->bLength;
+       }
+       dev_err(&interface->dev, "sample format descriptor not found\n");
+       return NULL;
+}
+
+static int detect_usb_format(struct ua101 *ua)
+{
+       const struct uac_format_type_i_discrete_descriptor *fmt_capture;
+       const struct uac_format_type_i_discrete_descriptor *fmt_playback;
+       const struct usb_endpoint_descriptor *epd;
+       unsigned int rate2;
+
+       fmt_capture = find_format_descriptor(ua->intf[INTF_CAPTURE]);
+       fmt_playback = find_format_descriptor(ua->intf[INTF_PLAYBACK]);
+       if (!fmt_capture || !fmt_playback)
+               return -ENXIO;
+
+       switch (fmt_capture->bSubframeSize) {
+       case 3:
+               ua->format_bit = SNDRV_PCM_FMTBIT_S24_3LE;
+               break;
+       case 4:
+               ua->format_bit = SNDRV_PCM_FMTBIT_S32_LE;
+               break;
+       default:
+               dev_err(&ua->dev->dev, "sample width is not 24 or 32 bits\n");
+               return -ENXIO;
+       }
+       if (fmt_capture->bSubframeSize != fmt_playback->bSubframeSize) {
+               dev_err(&ua->dev->dev,
+                       "playback/capture sample widths do not match\n");
+               return -ENXIO;
+       }
+
+       if (fmt_capture->bBitResolution != 24 ||
+           fmt_playback->bBitResolution != 24) {
+               dev_err(&ua->dev->dev, "sample width is not 24 bits\n");
+               return -ENXIO;
+       }
+
+       ua->rate = combine_triple(fmt_capture->tSamFreq[0]);
+       rate2 = combine_triple(fmt_playback->tSamFreq[0]);
+       if (ua->rate != rate2) {
+               dev_err(&ua->dev->dev,
+                       "playback/capture rates do not match: %u/%u\n",
+                       rate2, ua->rate);
+               return -ENXIO;
+       }
+
+       switch (ua->dev->speed) {
+       case USB_SPEED_FULL:
+               ua->packets_per_second = 1000;
+               break;
+       case USB_SPEED_HIGH:
+               ua->packets_per_second = 8000;
+               break;
+       default:
+               dev_err(&ua->dev->dev, "unknown device speed\n");
+               return -ENXIO;
+       }
+
+       ua->capture.channels = fmt_capture->bNrChannels;
+       ua->playback.channels = fmt_playback->bNrChannels;
+       ua->capture.frame_bytes =
+               fmt_capture->bSubframeSize * ua->capture.channels;
+       ua->playback.frame_bytes =
+               fmt_playback->bSubframeSize * ua->playback.channels;
+
+       epd = &ua->intf[INTF_CAPTURE]->altsetting[1].endpoint[0].desc;
+       if (!usb_endpoint_is_isoc_in(epd)) {
+               dev_err(&ua->dev->dev, "invalid capture endpoint\n");
+               return -ENXIO;
+       }
+       ua->capture.usb_pipe = usb_rcvisocpipe(ua->dev, usb_endpoint_num(epd));
+       ua->capture.max_packet_bytes = le16_to_cpu(epd->wMaxPacketSize);
+
+       epd = &ua->intf[INTF_PLAYBACK]->altsetting[1].endpoint[0].desc;
+       if (!usb_endpoint_is_isoc_out(epd)) {
+               dev_err(&ua->dev->dev, "invalid playback endpoint\n");
+               return -ENXIO;
+       }
+       ua->playback.usb_pipe = usb_sndisocpipe(ua->dev, usb_endpoint_num(epd));
+       ua->playback.max_packet_bytes = le16_to_cpu(epd->wMaxPacketSize);
+       return 0;
+}
+
+static int alloc_stream_buffers(struct ua101 *ua, struct ua101_stream *stream)
+{
+       unsigned int remaining_packets, packets, packets_per_page, i;
+       size_t size;
+
+       stream->queue_length = queue_length;
+       stream->queue_length = max(stream->queue_length,
+                                  (unsigned int)MIN_QUEUE_LENGTH);
+       stream->queue_length = min(stream->queue_length,
+                                  (unsigned int)MAX_QUEUE_LENGTH);
+
+       /*
+        * The cache pool sizes used by usb_buffer_alloc() (128, 512, 2048) are
+        * quite bad when used with the packet sizes of this device (e.g. 280,
+        * 520, 624).  Therefore, we allocate and subdivide entire pages, using
+        * a smaller buffer only for the last chunk.
+        */
+       remaining_packets = stream->queue_length;
+       packets_per_page = PAGE_SIZE / stream->max_packet_bytes;
+       for (i = 0; i < ARRAY_SIZE(stream->buffers); ++i) {
+               packets = min(remaining_packets, packets_per_page);
+               size = packets * stream->max_packet_bytes;
+               stream->buffers[i].addr =
+                       usb_buffer_alloc(ua->dev, size, GFP_KERNEL,
+                                        &stream->buffers[i].dma);
+               if (!stream->buffers[i].addr)
+                       return -ENOMEM;
+               stream->buffers[i].size = size;
+               remaining_packets -= packets;
+               if (!remaining_packets)
+                       break;
+       }
+       if (remaining_packets) {
+               dev_err(&ua->dev->dev, "too many packets\n");
+               return -ENXIO;
+       }
+       return 0;
+}
+
+static void free_stream_buffers(struct ua101 *ua, struct ua101_stream *stream)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(stream->buffers); ++i)
+               usb_buffer_free(ua->dev,
+                               stream->buffers[i].size,
+                               stream->buffers[i].addr,
+                               stream->buffers[i].dma);
+}
+
+static int alloc_stream_urbs(struct ua101 *ua, struct ua101_stream *stream,
+                            void (*urb_complete)(struct urb *))
+{
+       unsigned max_packet_size = stream->max_packet_bytes;
+       struct ua101_urb *urb;
+       unsigned int b, u = 0;
+
+       for (b = 0; b < ARRAY_SIZE(stream->buffers); ++b) {
+               unsigned int size = stream->buffers[b].size;
+               u8 *addr = stream->buffers[b].addr;
+               dma_addr_t dma = stream->buffers[b].dma;
+
+               while (size >= max_packet_size) {
+                       if (u >= stream->queue_length)
+                               goto bufsize_error;
+                       urb = kmalloc(sizeof(*urb), GFP_KERNEL);
+                       if (!urb)
+                               return -ENOMEM;
+                       usb_init_urb(&urb->urb);
+                       urb->urb.dev = ua->dev;
+                       urb->urb.pipe = stream->usb_pipe;
+                       urb->urb.transfer_flags = URB_ISO_ASAP |
+                                       URB_NO_TRANSFER_DMA_MAP;
+                       urb->urb.transfer_buffer = addr;
+                       urb->urb.transfer_dma = dma;
+                       urb->urb.transfer_buffer_length = max_packet_size;
+                       urb->urb.number_of_packets = 1;
+                       urb->urb.interval = 1;
+                       urb->urb.context = ua;
+                       urb->urb.complete = urb_complete;
+                       urb->urb.iso_frame_desc[0].offset = 0;
+                       urb->urb.iso_frame_desc[0].length = max_packet_size;
+                       stream->urbs[u++] = urb;
+                       size -= max_packet_size;
+                       addr += max_packet_size;
+                       dma += max_packet_size;
+               }
+       }
+       if (u == stream->queue_length)
+               return 0;
+bufsize_error:
+       dev_err(&ua->dev->dev, "internal buffer size error\n");
+       return -ENXIO;
+}
+
+static void free_stream_urbs(struct ua101_stream *stream)
+{
+       unsigned int i;
+
+       for (i = 0; i < stream->queue_length; ++i)
+               kfree(stream->urbs[i]);
+}
+
+static void free_usb_related_resources(struct ua101 *ua,
+                                      struct usb_interface *interface)
+{
+       unsigned int i;
+
+       free_stream_urbs(&ua->capture);
+       free_stream_urbs(&ua->playback);
+       free_stream_buffers(ua, &ua->capture);
+       free_stream_buffers(ua, &ua->playback);
+
+       for (i = 0; i < ARRAY_SIZE(ua->intf); ++i)
+               if (ua->intf[i]) {
+                       usb_set_intfdata(ua->intf[i], NULL);
+                       if (ua->intf[i] != interface)
+                               usb_driver_release_interface(&ua101_driver,
+                                                            ua->intf[i]);
+               }
+}
+
+static void ua101_card_free(struct snd_card *card)
+{
+       struct ua101 *ua = card->private_data;
+
+       mutex_destroy(&ua->mutex);
+}
+
+static int ua101_probe(struct usb_interface *interface,
+                      const struct usb_device_id *usb_id)
+{
+       static const struct snd_usb_midi_endpoint_info midi_ep = {
+               .out_cables = 0x0001,
+               .in_cables = 0x0001
+       };
+       static const struct snd_usb_audio_quirk midi_quirk = {
+               .type = QUIRK_MIDI_FIXED_ENDPOINT,
+               .data = &midi_ep
+       };
+       struct snd_card *card;
+       struct ua101 *ua;
+       unsigned int card_index, i;
+       char usb_path[32];
+       int err;
+
+       if (interface->altsetting->desc.bInterfaceNumber != 0)
+               return -ENODEV;
+
+       mutex_lock(&devices_mutex);
+
+       for (card_index = 0; card_index < SNDRV_CARDS; ++card_index)
+               if (enable[card_index] && !(devices_used & (1 << card_index)))
+                       break;
+       if (card_index >= SNDRV_CARDS) {
+               mutex_unlock(&devices_mutex);
+               return -ENOENT;
+       }
+       err = snd_card_create(index[card_index], id[card_index], THIS_MODULE,
+                             sizeof(*ua), &card);
+       if (err < 0) {
+               mutex_unlock(&devices_mutex);
+               return err;
+       }
+       card->private_free = ua101_card_free;
+       ua = card->private_data;
+       ua->dev = interface_to_usbdev(interface);
+       ua->card = card;
+       ua->card_index = card_index;
+       INIT_LIST_HEAD(&ua->midi_list);
+       spin_lock_init(&ua->lock);
+       mutex_init(&ua->mutex);
+       INIT_LIST_HEAD(&ua->ready_playback_urbs);
+       tasklet_init(&ua->playback_tasklet,
+                    playback_tasklet, (unsigned long)ua);
+       init_waitqueue_head(&ua->alsa_capture_wait);
+       init_waitqueue_head(&ua->rate_feedback_wait);
+       init_waitqueue_head(&ua->alsa_playback_wait);
+
+#ifdef UA1A_HACK
+       if (ua->dev->descriptor.idProduct == cpu_to_le16(0x0018)) {
+               ua->intf[2] = interface;
+               ua->intf[0] = usb_ifnum_to_if(ua->dev, 1);
+               ua->intf[1] = usb_ifnum_to_if(ua->dev, 2);
+               usb_driver_claim_interface(&ua101_driver, ua->intf[0], ua);
+               usb_driver_claim_interface(&ua101_driver, ua->intf[1], ua);
+       } else {
+#endif
+       ua->intf[0] = interface;
+       for (i = 1; i < ARRAY_SIZE(ua->intf); ++i) {
+               ua->intf[i] = usb_ifnum_to_if(ua->dev, i);
+               if (!ua->intf[i]) {
+                       dev_err(&ua->dev->dev, "interface %u not found\n", i);
+                       err = -ENXIO;
+                       goto probe_error;
+               }
+               err = usb_driver_claim_interface(&ua101_driver,
+                                                ua->intf[i], ua);
+               if (err < 0) {
+                       ua->intf[i] = NULL;
+                       err = -EBUSY;
+                       goto probe_error;
+               }
+       }
+#ifdef UA1A_HACK
+       }
+#endif
+
+       snd_card_set_dev(card, &interface->dev);
+
+#ifdef UA1A_HACK
+       if (ua->dev->descriptor.idProduct == cpu_to_le16(0x0018)) {
+               ua->format_bit = SNDRV_PCM_FMTBIT_S16_LE;
+               ua->rate = 44100;
+               ua->packets_per_second = 1000;
+               ua->capture.channels = 2;
+               ua->playback.channels = 2;
+               ua->capture.frame_bytes = 4;
+               ua->playback.frame_bytes = 4;
+               ua->capture.usb_pipe = usb_rcvisocpipe(ua->dev, 2);
+               ua->playback.usb_pipe = usb_sndisocpipe(ua->dev, 1);
+               ua->capture.max_packet_bytes = 192;
+               ua->playback.max_packet_bytes = 192;
+       } else {
+#endif
+       err = detect_usb_format(ua);
+       if (err < 0)
+               goto probe_error;
+#ifdef UA1A_HACK
+       }
+#endif
+
+       strcpy(card->driver, "UA-101");
+       strcpy(card->shortname, "UA-101");
+       usb_make_path(ua->dev, usb_path, sizeof(usb_path));
+       snprintf(ua->card->longname, sizeof(ua->card->longname),
+                "EDIROL UA-101 (serial %s), %u Hz at %s, %s speed",
+                ua->dev->serial ? ua->dev->serial : "?", ua->rate, usb_path,
+                ua->dev->speed == USB_SPEED_HIGH ? "high" : "full");
+
+       err = alloc_stream_buffers(ua, &ua->capture);
+       if (err < 0)
+               goto probe_error;
+       err = alloc_stream_buffers(ua, &ua->playback);
+       if (err < 0)
+               goto probe_error;
+
+       err = alloc_stream_urbs(ua, &ua->capture, capture_urb_complete);
+       if (err < 0)
+               goto probe_error;
+       err = alloc_stream_urbs(ua, &ua->playback, playback_urb_complete);
+       if (err < 0)
+               goto probe_error;
+
+       err = snd_pcm_new(card, "UA-101", 0, 1, 1, &ua->pcm);
+       if (err < 0)
+               goto probe_error;
+       ua->pcm->private_data = ua;
+       strcpy(ua->pcm->name, "UA-101");
+       snd_pcm_set_ops(ua->pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_pcm_ops);
+       snd_pcm_set_ops(ua->pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_pcm_ops);
+
+#ifdef UA1A_HACK
+       if (ua->dev->descriptor.idProduct != cpu_to_le16(0x0018)) {
+#endif
+       err = snd_usbmidi_create(card, ua->intf[INTF_MIDI],
+                                &ua->midi_list, &midi_quirk);
+       if (err < 0)
+               goto probe_error;
+#ifdef UA1A_HACK
+       }
+#endif
+
+       err = snd_card_register(card);
+       if (err < 0)
+               goto probe_error;
+
+       usb_set_intfdata(interface, ua);
+       devices_used |= 1 << card_index;
+
+       mutex_unlock(&devices_mutex);
+       return 0;
+
+probe_error:
+       free_usb_related_resources(ua, interface);
+       snd_card_free(card);
+       mutex_unlock(&devices_mutex);
+       return err;
+}
+
+static void ua101_disconnect(struct usb_interface *interface)
+{
+       struct ua101 *ua = usb_get_intfdata(interface);
+       struct list_head *midi;
+
+       if (!ua)
+               return;
+
+       mutex_lock(&devices_mutex);
+
+       set_bit(DISCONNECTED, &ua->states);
+       wake_up(&ua->rate_feedback_wait);
+
+       /* make sure that userspace cannot create new requests */
+       snd_card_disconnect(ua->card);
+
+       /* make sure that there are no pending USB requests */
+       __list_for_each(midi, &ua->midi_list)
+               snd_usbmidi_disconnect(midi);
+       abort_alsa_playback(ua);
+       abort_alsa_capture(ua);
+       mutex_lock(&ua->mutex);
+       stop_usb_playback(ua);
+       stop_usb_capture(ua);
+       mutex_unlock(&ua->mutex);
+
+       free_usb_related_resources(ua, interface);
+
+       devices_used &= ~(1 << ua->card_index);
+
+       snd_card_free_when_closed(ua->card);
+
+       mutex_unlock(&devices_mutex);
+}
+
+static struct usb_device_id ua101_ids[] = {
+#ifdef UA1A_HACK
+       { USB_DEVICE(0x0582, 0x0018) },
+#endif
+       { USB_DEVICE(0x0582, 0x007d) },
+       { USB_DEVICE(0x0582, 0x008d) },
+       { }
+};
+MODULE_DEVICE_TABLE(usb, ua101_ids);
+
+static struct usb_driver ua101_driver = {
+       .name = "snd-ua101",
+       .id_table = ua101_ids,
+       .probe = ua101_probe,
+       .disconnect = ua101_disconnect,
+#if 0
+       .suspend = ua101_suspend,
+       .resume = ua101_resume,
+#endif
+};
+
+static int __init alsa_card_ua101_init(void)
+{
+       return usb_register(&ua101_driver);
+}
+
+static void __exit alsa_card_ua101_exit(void)
+{
+       usb_deregister(&ua101_driver);
+       mutex_destroy(&devices_mutex);
+}
+
+module_init(alsa_card_ua101_init);
+module_exit(alsa_card_ua101_exit);
index 9edef4684978f43285bd6e076532ab795cfb9ccb..c539f7fe292f008ba5d37a45e7d04d864d12baaf 100644 (file)
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/usb.h>
-#include <linux/vmalloc.h>
 #include <linux/moduleparam.h>
 #include <linux/mutex.h>
+#include <linux/usb/audio.h>
+#include <linux/usb/ch9.h>
+
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/pcm.h>
@@ -170,11 +172,12 @@ struct snd_usb_substream {
        unsigned int curpacksize;       /* current packet size in bytes (for capture) */
        unsigned int curframesize;      /* current packet size in frames (for capture) */
        unsigned int fill_max: 1;       /* fill max packet size always */
+       unsigned int txfr_quirk:1;      /* allow sub-frame alignment */
        unsigned int fmt_type;          /* USB audio format type (1-3) */
 
        unsigned int running: 1;        /* running status */
 
-       unsigned int hwptr_done;                        /* processed frame position in the buffer */
+       unsigned int hwptr_done;        /* processed byte position in the buffer */
        unsigned int transfer_done;             /* processed frames since last period update */
        unsigned long active_mask;      /* bitmask of active urbs */
        unsigned long unlink_mask;      /* bitmask of unlinked urbs */
@@ -343,7 +346,7 @@ static int retire_capture_urb(struct snd_usb_substream *subs,
        unsigned long flags;
        unsigned char *cp;
        int i;
-       unsigned int stride, len, oldptr;
+       unsigned int stride, frames, bytes, oldptr;
        int period_elapsed = 0;
 
        stride = runtime->frame_bits >> 3;
@@ -354,29 +357,39 @@ static int retire_capture_urb(struct snd_usb_substream *subs,
                        snd_printd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status);
                        // continue;
                }
-               len = urb->iso_frame_desc[i].actual_length / stride;
-               if (! len)
-                       continue;
+               bytes = urb->iso_frame_desc[i].actual_length;
+               frames = bytes / stride;
+               if (!subs->txfr_quirk)
+                       bytes = frames * stride;
+               if (bytes % (runtime->sample_bits >> 3) != 0) {
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+                       int oldbytes = bytes;
+#endif
+                       bytes = frames * stride;
+                       snd_printdd(KERN_ERR "Corrected urb data len. %d->%d\n",
+                                                       oldbytes, bytes);
+               }
                /* update the current pointer */
                spin_lock_irqsave(&subs->lock, flags);
                oldptr = subs->hwptr_done;
-               subs->hwptr_done += len;
-               if (subs->hwptr_done >= runtime->buffer_size)
-                       subs->hwptr_done -= runtime->buffer_size;
-               subs->transfer_done += len;
+               subs->hwptr_done += bytes;
+               if (subs->hwptr_done >= runtime->buffer_size * stride)
+                       subs->hwptr_done -= runtime->buffer_size * stride;
+               frames = (bytes + (oldptr % stride)) / stride;
+               subs->transfer_done += frames;
                if (subs->transfer_done >= runtime->period_size) {
                        subs->transfer_done -= runtime->period_size;
                        period_elapsed = 1;
                }
                spin_unlock_irqrestore(&subs->lock, flags);
                /* copy a data chunk */
-               if (oldptr + len > runtime->buffer_size) {
-                       unsigned int cnt = runtime->buffer_size - oldptr;
-                       unsigned int blen = cnt * stride;
-                       memcpy(runtime->dma_area + oldptr * stride, cp, blen);
-                       memcpy(runtime->dma_area, cp + blen, len * stride - blen);
+               if (oldptr + bytes > runtime->buffer_size * stride) {
+                       unsigned int bytes1 =
+                                       runtime->buffer_size * stride - oldptr;
+                       memcpy(runtime->dma_area + oldptr, cp, bytes1);
+                       memcpy(runtime->dma_area, cp + bytes1, bytes - bytes1);
                } else {
-                       memcpy(runtime->dma_area + oldptr * stride, cp, len * stride);
+                       memcpy(runtime->dma_area + oldptr, cp, bytes);
                }
        }
        if (period_elapsed)
@@ -563,34 +576,34 @@ static int prepare_playback_urb(struct snd_usb_substream *subs,
                                struct snd_pcm_runtime *runtime,
                                struct urb *urb)
 {
-       int i, stride, offs;
-       unsigned int counts;
+       int i, stride;
+       unsigned int counts, frames, bytes;
        unsigned long flags;
        int period_elapsed = 0;
        struct snd_urb_ctx *ctx = urb->context;
 
        stride = runtime->frame_bits >> 3;
 
-       offs = 0;
+       frames = 0;
        urb->dev = ctx->subs->dev; /* we need to set this at each time */
        urb->number_of_packets = 0;
        spin_lock_irqsave(&subs->lock, flags);
        for (i = 0; i < ctx->packets; i++) {
                counts = snd_usb_audio_next_packet_size(subs);
                /* set up descriptor */
-               urb->iso_frame_desc[i].offset = offs * stride;
+               urb->iso_frame_desc[i].offset = frames * stride;
                urb->iso_frame_desc[i].length = counts * stride;
-               offs += counts;
+               frames += counts;
                urb->number_of_packets++;
                subs->transfer_done += counts;
                if (subs->transfer_done >= runtime->period_size) {
                        subs->transfer_done -= runtime->period_size;
                        period_elapsed = 1;
-                       if (subs->fmt_type == USB_FORMAT_TYPE_II) {
+                       if (subs->fmt_type == UAC_FORMAT_TYPE_II) {
                                if (subs->transfer_done > 0) {
                                        /* FIXME: fill-max mode is not
                                         * supported yet */
-                                       offs -= subs->transfer_done;
+                                       frames -= subs->transfer_done;
                                        counts -= subs->transfer_done;
                                        urb->iso_frame_desc[i].length =
                                                counts * stride;
@@ -600,7 +613,7 @@ static int prepare_playback_urb(struct snd_usb_substream *subs,
                                if (i < ctx->packets) {
                                        /* add a transfer delimiter */
                                        urb->iso_frame_desc[i].offset =
-                                               offs * stride;
+                                               frames * stride;
                                        urb->iso_frame_desc[i].length = 0;
                                        urb->number_of_packets++;
                                }
@@ -610,26 +623,25 @@ static int prepare_playback_urb(struct snd_usb_substream *subs,
                if (period_elapsed) /* finish at the period boundary */
                        break;
        }
-       if (subs->hwptr_done + offs > runtime->buffer_size) {
+       bytes = frames * stride;
+       if (subs->hwptr_done + bytes > runtime->buffer_size * stride) {
                /* err, the transferred area goes over buffer boundary. */
-               unsigned int len = runtime->buffer_size - subs->hwptr_done;
+               unsigned int bytes1 =
+                       runtime->buffer_size * stride - subs->hwptr_done;
                memcpy(urb->transfer_buffer,
-                      runtime->dma_area + subs->hwptr_done * stride,
-                      len * stride);
-               memcpy(urb->transfer_buffer + len * stride,
-                      runtime->dma_area,
-                      (offs - len) * stride);
+                      runtime->dma_area + subs->hwptr_done, bytes1);
+               memcpy(urb->transfer_buffer + bytes1,
+                      runtime->dma_area, bytes - bytes1);
        } else {
                memcpy(urb->transfer_buffer,
-                      runtime->dma_area + subs->hwptr_done * stride,
-                      offs * stride);
+                      runtime->dma_area + subs->hwptr_done, bytes);
        }
-       subs->hwptr_done += offs;
-       if (subs->hwptr_done >= runtime->buffer_size)
-               subs->hwptr_done -= runtime->buffer_size;
-       runtime->delay += offs;
+       subs->hwptr_done += bytes;
+       if (subs->hwptr_done >= runtime->buffer_size * stride)
+               subs->hwptr_done -= runtime->buffer_size * stride;
+       runtime->delay += frames;
        spin_unlock_irqrestore(&subs->lock, flags);
-       urb->transfer_buffer_length = offs * stride;
+       urb->transfer_buffer_length = bytes;
        if (period_elapsed)
                snd_pcm_period_elapsed(subs->pcm_substream);
        return 0;
@@ -735,41 +747,6 @@ static void snd_complete_sync_urb(struct urb *urb)
 }
 
 
-/* get the physical page pointer at the given offset */
-static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
-                                            unsigned long offset)
-{
-       void *pageptr = subs->runtime->dma_area + offset;
-       return vmalloc_to_page(pageptr);
-}
-
-/* allocate virtual buffer; may be called more than once */
-static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t size)
-{
-       struct snd_pcm_runtime *runtime = subs->runtime;
-       if (runtime->dma_area) {
-               if (runtime->dma_bytes >= size)
-                       return 0; /* already large enough */
-               vfree(runtime->dma_area);
-       }
-       runtime->dma_area = vmalloc_user(size);
-       if (!runtime->dma_area)
-               return -ENOMEM;
-       runtime->dma_bytes = size;
-       return 0;
-}
-
-/* free virtual buffer; may be called more than once */
-static int snd_pcm_free_vmalloc_buffer(struct snd_pcm_substream *subs)
-{
-       struct snd_pcm_runtime *runtime = subs->runtime;
-
-       vfree(runtime->dma_area);
-       runtime->dma_area = NULL;
-       return 0;
-}
-
-
 /*
  * unlink active urbs.
  */
@@ -937,18 +914,18 @@ static int wait_clear_urbs(struct snd_usb_substream *subs)
 
 
 /*
- * return the current pcm pointer.  just return the hwptr_done value.
+ * return the current pcm pointer.  just based on the hwptr_done value.
  */
 static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream)
 {
        struct snd_usb_substream *subs;
-       snd_pcm_uframes_t hwptr_done;
+       unsigned int hwptr_done;
        
        subs = (struct snd_usb_substream *)substream->runtime->private_data;
        spin_lock(&subs->lock);
        hwptr_done = subs->hwptr_done;
        spin_unlock(&subs->lock);
-       return hwptr_done;
+       return hwptr_done / (substream->runtime->frame_bits >> 3);
 }
 
 
@@ -1130,7 +1107,7 @@ static int init_substream_urbs(struct snd_usb_substream *subs, unsigned int peri
                u->packets = (i + 1) * total_packs / subs->nurbs
                        - i * total_packs / subs->nurbs;
                u->buffer_size = maxsize * u->packets;
-               if (subs->fmt_type == USB_FORMAT_TYPE_II)
+               if (subs->fmt_type == UAC_FORMAT_TYPE_II)
                        u->packets++; /* for transfer delimiter */
                u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);
                if (!u->urb)
@@ -1206,7 +1183,7 @@ static struct audioformat *find_format(struct snd_usb_substream *subs, unsigned
                        if (i >= fp->nr_rates)
                                continue;
                }
-               attr = fp->ep_attr & EP_ATTR_MASK;
+               attr = fp->ep_attr & USB_ENDPOINT_SYNCTYPE;
                if (! found) {
                        found = fp;
                        cur_attr = attr;
@@ -1218,14 +1195,14 @@ static struct audioformat *find_format(struct snd_usb_substream *subs, unsigned
                 * M-audio audiophile USB.
                 */
                if (attr != cur_attr) {
-                       if ((attr == EP_ATTR_ASYNC &&
+                       if ((attr == USB_ENDPOINT_SYNC_ASYNC &&
                             subs->direction == SNDRV_PCM_STREAM_PLAYBACK) ||
-                           (attr == EP_ATTR_ADAPTIVE &&
+                           (attr == USB_ENDPOINT_SYNC_ADAPTIVE &&
                             subs->direction == SNDRV_PCM_STREAM_CAPTURE))
                                continue;
-                       if ((cur_attr == EP_ATTR_ASYNC &&
+                       if ((cur_attr == USB_ENDPOINT_SYNC_ASYNC &&
                             subs->direction == SNDRV_PCM_STREAM_PLAYBACK) ||
-                           (cur_attr == EP_ATTR_ADAPTIVE &&
+                           (cur_attr == USB_ENDPOINT_SYNC_ADAPTIVE &&
                             subs->direction == SNDRV_PCM_STREAM_CAPTURE)) {
                                found = fp;
                                cur_attr = attr;
@@ -1255,11 +1232,11 @@ static int init_usb_pitch(struct usb_device *dev, int iface,
 
        ep = get_endpoint(alts, 0)->bEndpointAddress;
        /* if endpoint has pitch control, enable it */
-       if (fmt->attributes & EP_CS_ATTR_PITCH_CONTROL) {
+       if (fmt->attributes & UAC_EP_CS_ATTR_PITCH_CONTROL) {
                data[0] = 1;
-               if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR,
+               if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR,
                                           USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
-                                          PITCH_CONTROL << 8, ep, data, 1, 1000)) < 0) {
+                                          UAC_EP_CS_ATTR_PITCH_CONTROL << 8, ep, data, 1, 1000)) < 0) {
                        snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH\n",
                                   dev->devnum, iface, ep);
                        return err;
@@ -1278,21 +1255,21 @@ static int init_usb_sample_rate(struct usb_device *dev, int iface,
 
        ep = get_endpoint(alts, 0)->bEndpointAddress;
        /* if endpoint has sampling rate control, set it */
-       if (fmt->attributes & EP_CS_ATTR_SAMPLE_RATE) {
+       if (fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE) {
                int crate;
                data[0] = rate;
                data[1] = rate >> 8;
                data[2] = rate >> 16;
-               if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR,
+               if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR,
                                           USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
-                                          SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
+                                          UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, data, 3, 1000)) < 0) {
                        snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n",
                                   dev->devnum, iface, fmt->altsetting, rate, ep);
                        return err;
                }
-               if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR,
+               if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR,
                                           USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
-                                          SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
+                                          UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, data, 3, 1000)) < 0) {
                        snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n",
                                   dev->devnum, iface, fmt->altsetting, ep);
                        return 0; /* some devices don't support reading */
@@ -1306,6 +1283,47 @@ static int init_usb_sample_rate(struct usb_device *dev, int iface,
        return 0;
 }
 
+/*
+ * For E-Mu 0404USB/0202USB/TrackerPre sample rate should be set for device,
+ * not for interface.
+ */
+static void set_format_emu_quirk(struct snd_usb_substream *subs,
+                                struct audioformat *fmt)
+{
+       unsigned char emu_samplerate_id = 0;
+
+       /* When capture is active
+        * sample rate shouldn't be changed
+        * by playback substream
+        */
+       if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) {
+               if (subs->stream->substream[SNDRV_PCM_STREAM_CAPTURE].interface != -1)
+                       return;
+       }
+
+       switch (fmt->rate_min) {
+       case 48000:
+               emu_samplerate_id = EMU_QUIRK_SR_48000HZ;
+               break;
+       case 88200:
+               emu_samplerate_id = EMU_QUIRK_SR_88200HZ;
+               break;
+       case 96000:
+               emu_samplerate_id = EMU_QUIRK_SR_96000HZ;
+               break;
+       case 176400:
+               emu_samplerate_id = EMU_QUIRK_SR_176400HZ;
+               break;
+       case 192000:
+               emu_samplerate_id = EMU_QUIRK_SR_192000HZ;
+               break;
+       default:
+               emu_samplerate_id = EMU_QUIRK_SR_44100HZ;
+               break;
+       }
+       snd_emuusb_set_samplerate(subs->stream->chip, emu_samplerate_id);
+}
+
 /*
  * find a matching format and set up the interface
  */
@@ -1369,9 +1387,9 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
         * descriptors which fool us.  if it has only one EP,
         * assume it as adaptive-out or sync-in.
         */
-       attr = fmt->ep_attr & EP_ATTR_MASK;
-       if (((is_playback && attr == EP_ATTR_ASYNC) ||
-            (! is_playback && attr == EP_ATTR_ADAPTIVE)) &&
+       attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE;
+       if (((is_playback && attr == USB_ENDPOINT_SYNC_ASYNC) ||
+            (! is_playback && attr == USB_ENDPOINT_SYNC_ADAPTIVE)) &&
            altsd->bNumEndpoints >= 2) {
                /* check sync-pipe endpoint */
                /* ... and check descriptor size before accessing bSynchAddress
@@ -1411,7 +1429,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
        }
 
        /* always fill max packet size */
-       if (fmt->attributes & EP_CS_ATTR_FILL_MAX)
+       if (fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX)
                subs->fill_max = 1;
 
        if ((err = init_usb_pitch(dev, subs->interface, alts, fmt)) < 0)
@@ -1419,6 +1437,14 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
 
        subs->cur_audiofmt = fmt;
 
+       switch (subs->stream->chip->usb_id) {
+       case USB_ID(0x041e, 0x3f02): /* E-Mu 0202 USB */
+       case USB_ID(0x041e, 0x3f04): /* E-Mu 0404 USB */
+       case USB_ID(0x041e, 0x3f0a): /* E-Mu Tracker Pre */
+               set_format_emu_quirk(subs, fmt);
+               break;
+       }
+
 #if 0
        printk(KERN_DEBUG
               "setting done: format = %d, rate = %d..%d, channels = %d\n",
@@ -1449,8 +1475,8 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
        unsigned int channels, rate, format;
        int ret, changed;
 
-       ret = snd_pcm_alloc_vmalloc_buffer(substream,
-                                          params_buffer_bytes(hw_params));
+       ret = snd_pcm_lib_alloc_vmalloc_buffer(substream,
+                                              params_buffer_bytes(hw_params));
        if (ret < 0)
                return ret;
 
@@ -1507,7 +1533,7 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream)
        subs->period_bytes = 0;
        if (!subs->stream->chip->shutdown)
                release_substream_urbs(subs, 0);
-       return snd_pcm_free_vmalloc_buffer(substream);
+       return snd_pcm_lib_free_vmalloc_buffer(substream);
 }
 
 /*
@@ -1861,7 +1887,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
                        runtime->hw.channels_min = fp->channels;
                if (runtime->hw.channels_max < fp->channels)
                        runtime->hw.channels_max = fp->channels;
-               if (fp->fmt_type == USB_FORMAT_TYPE_II && fp->frame_size > 0) {
+               if (fp->fmt_type == UAC_FORMAT_TYPE_II && fp->frame_size > 0) {
                        /* FIXME: there might be more than one audio formats... */
                        runtime->hw.period_bytes_min = runtime->hw.period_bytes_max =
                                fp->frame_size;
@@ -1973,7 +1999,8 @@ static struct snd_pcm_ops snd_usb_playback_ops = {
        .prepare =      snd_usb_pcm_prepare,
        .trigger =      snd_usb_pcm_playback_trigger,
        .pointer =      snd_usb_pcm_pointer,
-       .page =         snd_pcm_get_vmalloc_page,
+       .page =         snd_pcm_lib_get_vmalloc_page,
+       .mmap =         snd_pcm_lib_mmap_vmalloc,
 };
 
 static struct snd_pcm_ops snd_usb_capture_ops = {
@@ -1985,7 +2012,8 @@ static struct snd_pcm_ops snd_usb_capture_ops = {
        .prepare =      snd_usb_pcm_prepare,
        .trigger =      snd_usb_pcm_capture_trigger,
        .pointer =      snd_usb_pcm_pointer,
-       .page =         snd_pcm_get_vmalloc_page,
+       .page =         snd_pcm_lib_get_vmalloc_page,
+       .mmap =         snd_pcm_lib_mmap_vmalloc,
 };
 
 
@@ -2093,7 +2121,7 @@ static struct usb_device_id usb_audio_ids [] = {
 #include "usbquirks.h"
     { .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS),
       .bInterfaceClass = USB_CLASS_AUDIO,
-      .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL },
+      .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL },
     { }                                                /* Terminating entry */
 };
 
@@ -2132,7 +2160,7 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s
                snd_iprintf(buffer, "    Endpoint: %d %s (%s)\n",
                            fp->endpoint & USB_ENDPOINT_NUMBER_MASK,
                            fp->endpoint & USB_DIR_IN ? "IN" : "OUT",
-                           sync_types[(fp->ep_attr & EP_ATTR_MASK) >> 2]);
+                           sync_types[(fp->ep_attr & USB_ENDPOINT_SYNCTYPE) >> 2]);
                if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) {
                        snd_iprintf(buffer, "    Rates: %d - %d (continuous)\n",
                                    fp->rate_min, fp->rate_max);
@@ -2227,6 +2255,7 @@ static void init_substream(struct snd_usb_stream *as, int stream, struct audiofo
        subs->stream = as;
        subs->direction = stream;
        subs->dev = as->chip->dev;
+       subs->txfr_quirk = as->chip->txfr_quirk;
        if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) {
                subs->ops = audio_urb_ops[stream];
        } else {
@@ -2394,29 +2423,68 @@ static int is_big_endian_format(struct snd_usb_audio *chip, struct audioformat *
  * @format: the format tag (wFormatTag)
  * @fmt: the format type descriptor
  */
-static int parse_audio_format_i_type(struct snd_usb_audio *chip, struct audioformat *fp,
-                                    int format, unsigned char *fmt)
+static int parse_audio_format_i_type(struct snd_usb_audio *chip,
+                                    struct audioformat *fp,
+                                    int format, void *_fmt,
+                                    int protocol)
 {
-       int pcm_format;
+       int pcm_format, i;
        int sample_width, sample_bytes;
 
+       switch (protocol) {
+       case UAC_VERSION_1: {
+               struct uac_format_type_i_discrete_descriptor *fmt = _fmt;
+               sample_width = fmt->bBitResolution;
+               sample_bytes = fmt->bSubframeSize;
+               break;
+       }
+
+       case UAC_VERSION_2: {
+               struct uac_format_type_i_ext_descriptor *fmt = _fmt;
+               sample_width = fmt->bBitResolution;
+               sample_bytes = fmt->bSubslotSize;
+
+               /*
+                * FIXME
+                * USB audio class v2 devices specify a bitmap of possible
+                * audio formats rather than one fix value. For now, we just
+                * pick one of them and report that as the only possible
+                * value for this setting.
+                * The bit allocation map is in fact compatible to the
+                * wFormatTag of the v1 AS streaming descriptors, which is why
+                * we can simply map the matrix.
+                */
+
+               for (i = 0; i < 5; i++)
+                       if (format & (1UL << i)) {
+                               format = i + 1;
+                               break;
+                       }
+
+               break;
+       }
+
+       default:
+               return -EINVAL;
+       }
+
        /* FIXME: correct endianess and sign? */
        pcm_format = -1;
-       sample_width = fmt[6];
-       sample_bytes = fmt[5];
+
        switch (format) {
-       case 0: /* some devices don't define this correctly... */
+       case UAC_FORMAT_TYPE_I_UNDEFINED: /* some devices don't define this correctly... */
                snd_printdd(KERN_INFO "%d:%u:%d : format type 0 is detected, processed as PCM\n",
                            chip->dev->devnum, fp->iface, fp->altsetting);
                /* fall-through */
-       case USB_AUDIO_FORMAT_PCM:
+       case UAC_FORMAT_TYPE_I_PCM:
                if (sample_width > sample_bytes * 8) {
                        snd_printk(KERN_INFO "%d:%u:%d : sample bitwidth %d in over sample bytes %d\n",
                                   chip->dev->devnum, fp->iface, fp->altsetting,
                                   sample_width, sample_bytes);
                }
                /* check the format byte size */
-               switch (fmt[5]) {
+               printk(" XXXXX SAMPLE BYTES %d\n", sample_bytes);
+               switch (sample_bytes) {
                case 1:
                        pcm_format = SNDRV_PCM_FORMAT_S8;
                        break;
@@ -2437,12 +2505,12 @@ static int parse_audio_format_i_type(struct snd_usb_audio *chip, struct audiofor
                        break;
                default:
                        snd_printk(KERN_INFO "%d:%u:%d : unsupported sample bitwidth %d in %d bytes\n",
-                                  chip->dev->devnum, fp->iface,
-                                  fp->altsetting, sample_width, sample_bytes);
+                                  chip->dev->devnum, fp->iface, fp->altsetting,
+                                  sample_width, sample_bytes);
                        break;
                }
                break;
-       case USB_AUDIO_FORMAT_PCM8:
+       case UAC_FORMAT_TYPE_I_PCM8:
                pcm_format = SNDRV_PCM_FORMAT_U8;
 
                /* Dallas DS4201 workaround: it advertises U8 format, but really
@@ -2450,13 +2518,13 @@ static int parse_audio_format_i_type(struct snd_usb_audio *chip, struct audiofor
                if (chip->usb_id == USB_ID(0x04fa, 0x4201))
                        pcm_format = SNDRV_PCM_FORMAT_S8;
                break;
-       case USB_AUDIO_FORMAT_IEEE_FLOAT:
+       case UAC_FORMAT_TYPE_I_IEEE_FLOAT:
                pcm_format = SNDRV_PCM_FORMAT_FLOAT_LE;
                break;
-       case USB_AUDIO_FORMAT_ALAW:
+       case UAC_FORMAT_TYPE_I_ALAW:
                pcm_format = SNDRV_PCM_FORMAT_A_LAW;
                break;
-       case USB_AUDIO_FORMAT_MU_LAW:
+       case UAC_FORMAT_TYPE_I_MULAW:
                pcm_format = SNDRV_PCM_FORMAT_MU_LAW;
                break;
        default:
@@ -2470,7 +2538,7 @@ static int parse_audio_format_i_type(struct snd_usb_audio *chip, struct audiofor
 
 /*
  * parse the format descriptor and stores the possible sample rates
- * on the audioformat table.
+ * on the audioformat table (audio class v1).
  *
  * @dev: usb device
  * @fp: audioformat record
@@ -2478,13 +2546,13 @@ static int parse_audio_format_i_type(struct snd_usb_audio *chip, struct audiofor
  * @offset: the start offset of descriptor pointing the rate type
  *          (7 for type I and II, 8 for type II)
  */
-static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioformat *fp,
-                                   unsigned char *fmt, int offset)
+static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audioformat *fp,
+                                      unsigned char *fmt, int offset)
 {
        int nr_rates = fmt[offset];
 
        if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) {
-               snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n",
+               snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n",
                                   chip->dev->devnum, fp->iface, fp->altsetting);
                return -1;
        }
@@ -2534,15 +2602,88 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform
        return 0;
 }
 
+/*
+ * parse the format descriptor and stores the possible sample rates
+ * on the audioformat table (audio class v2).
+ */
+static int parse_audio_format_rates_v2(struct snd_usb_audio *chip,
+                                      struct audioformat *fp,
+                                      struct usb_host_interface *iface)
+{
+       struct usb_device *dev = chip->dev;
+       unsigned char tmp[2], *data;
+       int i, nr_rates, data_size, ret = 0;
+
+       /* get the number of sample rates first by only fetching 2 bytes */
+       ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE,
+                              USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+                              0x0100, chip->clock_id << 8, tmp, sizeof(tmp), 1000);
+
+       if (ret < 0) {
+               snd_printk(KERN_ERR "unable to retrieve number of sample rates\n");
+               goto err;
+       }
+
+       nr_rates = (tmp[1] << 8) | tmp[0];
+       data_size = 2 + 12 * nr_rates;
+       data = kzalloc(data_size, GFP_KERNEL);
+       if (!data) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       /* now get the full information */
+       ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE,
+                              USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+                              0x0100, chip->clock_id << 8, data, data_size, 1000);
+
+       if (ret < 0) {
+               snd_printk(KERN_ERR "unable to retrieve sample rate range\n");
+               ret = -EINVAL;
+               goto err_free;
+       }
+
+       fp->rate_table = kmalloc(sizeof(int) * nr_rates, GFP_KERNEL);
+       if (!fp->rate_table) {
+               ret = -ENOMEM;
+               goto err_free;
+       }
+
+       fp->nr_rates = 0;
+       fp->rate_min = fp->rate_max = 0;
+
+       for (i = 0; i < nr_rates; i++) {
+               int rate = combine_quad(&data[2 + 12 * i]);
+
+               fp->rate_table[fp->nr_rates] = rate;
+               if (!fp->rate_min || rate < fp->rate_min)
+                       fp->rate_min = rate;
+               if (!fp->rate_max || rate > fp->rate_max)
+                       fp->rate_max = rate;
+               fp->rates |= snd_pcm_rate_to_rate_bit(rate);
+               fp->nr_rates++;
+       }
+
+err_free:
+       kfree(data);
+err:
+       return ret;
+}
+
 /*
  * parse the format type I and III descriptors
  */
-static int parse_audio_format_i(struct snd_usb_audio *chip, struct audioformat *fp,
-                               int format, unsigned char *fmt)
+static int parse_audio_format_i(struct snd_usb_audio *chip,
+                               struct audioformat *fp,
+                               int format, void *_fmt,
+                               struct usb_host_interface *iface)
 {
-       int pcm_format;
+       struct usb_interface_descriptor *altsd = get_iface_desc(iface);
+       struct uac_format_type_i_discrete_descriptor *fmt = _fmt;
+       int protocol = altsd->bInterfaceProtocol;
+       int pcm_format, ret;
 
-       if (fmt[3] == USB_FORMAT_TYPE_III) {
+       if (fmt->bFormatType == UAC_FORMAT_TYPE_III) {
                /* FIXME: the format type is really IECxxx
                 *        but we give normal PCM format to get the existing
                 *        apps working...
@@ -2560,34 +2701,57 @@ static int parse_audio_format_i(struct snd_usb_audio *chip, struct audioformat *
                        pcm_format = SNDRV_PCM_FORMAT_S16_LE;
                }
        } else {
-               pcm_format = parse_audio_format_i_type(chip, fp, format, fmt);
+               pcm_format = parse_audio_format_i_type(chip, fp, format, fmt, protocol);
                if (pcm_format < 0)
                        return -1;
        }
+
        fp->format = pcm_format;
-       fp->channels = fmt[4];
+
+       /* gather possible sample rates */
+       /* audio class v1 reports possible sample rates as part of the
+        * proprietary class specific descriptor.
+        * audio class v2 uses class specific EP0 range requests for that.
+        */
+       switch (protocol) {
+       case UAC_VERSION_1:
+               fp->channels = fmt->bNrChannels;
+               ret = parse_audio_format_rates_v1(chip, fp, _fmt, 7);
+               break;
+       case UAC_VERSION_2:
+               /* fp->channels is already set in this case */
+               ret = parse_audio_format_rates_v2(chip, fp, iface);
+               break;
+       }
+
        if (fp->channels < 1) {
                snd_printk(KERN_ERR "%d:%u:%d : invalid channels %d\n",
                           chip->dev->devnum, fp->iface, fp->altsetting, fp->channels);
                return -1;
        }
-       return parse_audio_format_rates(chip, fp, fmt, 7);
+
+       return ret;
 }
 
 /*
- * prase the format type II descriptor
+ * parse the format type II descriptor
  */
-static int parse_audio_format_ii(struct snd_usb_audio *chip, struct audioformat *fp,
-                                int format, unsigned char *fmt)
+static int parse_audio_format_ii(struct snd_usb_audio *chip,
+                                struct audioformat *fp,
+                                int format, void *_fmt,
+                                struct usb_host_interface *iface)
 {
-       int brate, framesize;
+       int brate, framesize, ret;
+       struct usb_interface_descriptor *altsd = get_iface_desc(iface);
+       int protocol = altsd->bInterfaceProtocol;
+
        switch (format) {
-       case USB_AUDIO_FORMAT_AC3:
+       case UAC_FORMAT_TYPE_II_AC3:
                /* FIXME: there is no AC3 format defined yet */
                // fp->format = SNDRV_PCM_FORMAT_AC3;
                fp->format = SNDRV_PCM_FORMAT_U8; /* temporarily hack to receive byte streams */
                break;
-       case USB_AUDIO_FORMAT_MPEG:
+       case UAC_FORMAT_TYPE_II_MPEG:
                fp->format = SNDRV_PCM_FORMAT_MPEG;
                break;
        default:
@@ -2596,26 +2760,46 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip, struct audioformat
                fp->format = SNDRV_PCM_FORMAT_MPEG;
                break;
        }
+
        fp->channels = 1;
-       brate = combine_word(&fmt[4]);  /* fmt[4,5] : wMaxBitRate (in kbps) */
-       framesize = combine_word(&fmt[6]); /* fmt[6,7]: wSamplesPerFrame */
-       snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize);
-       fp->frame_size = framesize;
-       return parse_audio_format_rates(chip, fp, fmt, 8); /* fmt[8..] sample rates */
+
+       switch (protocol) {
+       case UAC_VERSION_1: {
+               struct uac_format_type_ii_discrete_descriptor *fmt = _fmt;
+               brate = le16_to_cpu(fmt->wMaxBitRate);
+               framesize = le16_to_cpu(fmt->wSamplesPerFrame);
+               snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize);
+               fp->frame_size = framesize;
+               ret = parse_audio_format_rates_v1(chip, fp, _fmt, 8); /* fmt[8..] sample rates */
+               break;
+       }
+       case UAC_VERSION_2: {
+               struct uac_format_type_ii_ext_descriptor *fmt = _fmt;
+               brate = le16_to_cpu(fmt->wMaxBitRate);
+               framesize = le16_to_cpu(fmt->wSamplesPerFrame);
+               snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize);
+               fp->frame_size = framesize;
+               ret = parse_audio_format_rates_v2(chip, fp, iface);
+               break;
+       }
+       }
+
+       return ret;
 }
 
 static int parse_audio_format(struct snd_usb_audio *chip, struct audioformat *fp,
-                             int format, unsigned char *fmt, int stream)
+                             int format, unsigned char *fmt, int stream,
+                             struct usb_host_interface *iface)
 {
        int err;
 
        switch (fmt[3]) {
-       case USB_FORMAT_TYPE_I:
-       case USB_FORMAT_TYPE_III:
-               err = parse_audio_format_i(chip, fp, format, fmt);
+       case UAC_FORMAT_TYPE_I:
+       case UAC_FORMAT_TYPE_III:
+               err = parse_audio_format_i(chip, fp, format, fmt, iface);
                break;
-       case USB_FORMAT_TYPE_II:
-               err = parse_audio_format_ii(chip, fp, format, fmt);
+       case UAC_FORMAT_TYPE_II:
+               err = parse_audio_format_ii(chip, fp, format, fmt, iface);
                break;
        default:
                snd_printd(KERN_INFO "%d:%u:%d : format type %d is not supported yet\n",
@@ -2633,7 +2817,7 @@ static int parse_audio_format(struct snd_usb_audio *chip, struct audioformat *fp
        if (chip->usb_id == USB_ID(0x041e, 0x3000) ||
            chip->usb_id == USB_ID(0x041e, 0x3020) ||
            chip->usb_id == USB_ID(0x041e, 0x3061)) {
-               if (fmt[3] == USB_FORMAT_TYPE_I &&
+               if (fmt[3] == UAC_FORMAT_TYPE_I &&
                    fp->rates != SNDRV_PCM_RATE_48000 &&
                    fp->rates != SNDRV_PCM_RATE_96000)
                        return -1;
@@ -2662,10 +2846,10 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
        struct usb_host_interface *alts;
        struct usb_interface_descriptor *altsd;
        int i, altno, err, stream;
-       int format;
+       int format = 0, num_channels = 0;
        struct audioformat *fp = NULL;
        unsigned char *fmt, *csep;
-       int num;
+       int num, protocol;
 
        dev = chip->dev;
 
@@ -2684,10 +2868,11 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
        for (i = 0; i < num; i++) {
                alts = &iface->altsetting[i];
                altsd = get_iface_desc(alts);
+               protocol = altsd->bInterfaceProtocol;
                /* skip invalid one */
                if ((altsd->bInterfaceClass != USB_CLASS_AUDIO &&
                     altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) ||
-                   (altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIO_STREAMING &&
+                   (altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING &&
                     altsd->bInterfaceSubClass != USB_SUBCLASS_VENDOR_SPEC) ||
                    altsd->bNumEndpoints < 1 ||
                    le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == 0)
@@ -2708,30 +2893,65 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
                        continue;
 
                /* get audio formats */
-               fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, AS_GENERAL);
-               if (!fmt) {
-                       snd_printk(KERN_ERR "%d:%u:%d : AS_GENERAL descriptor not found\n",
-                                  dev->devnum, iface_no, altno);
-                       continue;
+               switch (protocol) {
+               case UAC_VERSION_1: {
+                       struct uac_as_header_descriptor_v1 *as =
+                               snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL);
+
+                       if (!as) {
+                               snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n",
+                                          dev->devnum, iface_no, altno);
+                               continue;
+                       }
+
+                       if (as->bLength < sizeof(*as)) {
+                               snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n",
+                                          dev->devnum, iface_no, altno);
+                               continue;
+                       }
+
+                       format = le16_to_cpu(as->wFormatTag); /* remember the format value */
+                       break;
                }
 
-               if (fmt[0] < 7) {
-                       snd_printk(KERN_ERR "%d:%u:%d : invalid AS_GENERAL desc\n",
-                                  dev->devnum, iface_no, altno);
-                       continue;
+               case UAC_VERSION_2: {
+                       struct uac_as_header_descriptor_v2 *as =
+                               snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL);
+
+                       if (!as) {
+                               snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n",
+                                          dev->devnum, iface_no, altno);
+                               continue;
+                       }
+
+                       if (as->bLength < sizeof(*as)) {
+                               snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n",
+                                          dev->devnum, iface_no, altno);
+                               continue;
+                       }
+
+                       num_channels = as->bNrChannels;
+                       format = le32_to_cpu(as->bmFormats);
+
+                       break;
                }
 
-               format = (fmt[6] << 8) | fmt[5]; /* remember the format value */
+               default:
+                       snd_printk(KERN_ERR "%d:%u:%d : unknown interface protocol %04x\n",
+                                  dev->devnum, iface_no, altno, protocol);
+                       continue;
+               }
 
                /* get format type */
-               fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, FORMAT_TYPE);
+               fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_FORMAT_TYPE);
                if (!fmt) {
-                       snd_printk(KERN_ERR "%d:%u:%d : no FORMAT_TYPE desc\n",
+                       snd_printk(KERN_ERR "%d:%u:%d : no UAC_FORMAT_TYPE desc\n",
                                   dev->devnum, iface_no, altno);
                        continue;
                }
-               if (fmt[0] < 8) {
-                       snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n",
+               if (((protocol == UAC_VERSION_1) && (fmt[0] < 8)) ||
+                   ((protocol == UAC_VERSION_2) && (fmt[0] != 6))) {
+                       snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n",
                                   dev->devnum, iface_no, altno);
                        continue;
                }
@@ -2744,6 +2964,7 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
                if (fmt[4] == 1 && fmt[5] == 2 && altno == 2 && num == 3 &&
                    fp && fp->altsetting == 1 && fp->channels == 1 &&
                    fp->format == SNDRV_PCM_FORMAT_S16_LE &&
+                   protocol == UAC_VERSION_1 &&
                    le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) ==
                                                        fp->maxpacksize * 2)
                        continue;
@@ -2752,7 +2973,7 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
                /* Creamware Noah has this descriptor after the 2nd endpoint */
                if (!csep && altsd->bNumEndpoints >= 2)
                        csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT);
-               if (!csep || csep[0] < 7 || csep[2] != EP_GENERAL) {
+               if (!csep || csep[0] < 7 || csep[2] != UAC_EP_GENERAL) {
                        snd_printk(KERN_WARNING "%d:%u:%d : no or invalid"
                                   " class specific endpoint descriptor\n",
                                   dev->devnum, iface_no, altno);
@@ -2772,6 +2993,8 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
                fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
                fp->datainterval = parse_datainterval(chip, alts);
                fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
+               /* num_channels is only set for v2 interfaces */
+               fp->channels = num_channels;
                if (snd_usb_get_speed(dev) == USB_SPEED_HIGH)
                        fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1)
                                        * (fp->maxpacksize & 0x7ff);
@@ -2784,12 +3007,12 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
                        /* Optoplay sets the sample rate attribute although
                         * it seems not supporting it in fact.
                         */
-                       fp->attributes &= ~EP_CS_ATTR_SAMPLE_RATE;
+                       fp->attributes &= ~UAC_EP_CS_ATTR_SAMPLE_RATE;
                        break;
                case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */
                case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
                        /* doesn't set the sample rate attribute, but supports it */
-                       fp->attributes |= EP_CS_ATTR_SAMPLE_RATE;
+                       fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE;
                        break;
                case USB_ID(0x047f, 0x0ca1): /* plantronics headset */
                case USB_ID(0x077d, 0x07af): /* Griffin iMic (note that there is
@@ -2798,16 +3021,16 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
                 * plantronics headset and Griffin iMic have set adaptive-in
                 * although it's really not...
                 */
-                       fp->ep_attr &= ~EP_ATTR_MASK;
+                       fp->ep_attr &= ~USB_ENDPOINT_SYNCTYPE;
                        if (stream == SNDRV_PCM_STREAM_PLAYBACK)
-                               fp->ep_attr |= EP_ATTR_ADAPTIVE;
+                               fp->ep_attr |= USB_ENDPOINT_SYNC_ADAPTIVE;
                        else
-                               fp->ep_attr |= EP_ATTR_SYNC;
+                               fp->ep_attr |= USB_ENDPOINT_SYNC_SYNC;
                        break;
                }
 
                /* ok, let's parse further... */
-               if (parse_audio_format(chip, fp, format, fmt, stream) < 0) {
+               if (parse_audio_format(chip, fp, format, fmt, stream, alts) < 0) {
                        kfree(fp->rate_table);
                        kfree(fp);
                        continue;
@@ -2849,6 +3072,65 @@ static void snd_usb_stream_disconnect(struct list_head *head)
        }
 }
 
+static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int interface)
+{
+       struct usb_device *dev = chip->dev;
+       struct usb_host_interface *alts;
+       struct usb_interface_descriptor *altsd;
+       struct usb_interface *iface = usb_ifnum_to_if(dev, interface);
+
+       if (!iface) {
+               snd_printk(KERN_ERR "%d:%u:%d : does not exist\n",
+                          dev->devnum, ctrlif, interface);
+               return -EINVAL;
+       }
+
+       if (usb_interface_claimed(iface)) {
+               snd_printdd(KERN_INFO "%d:%d:%d: skipping, already claimed\n",
+                                               dev->devnum, ctrlif, interface);
+               return -EINVAL;
+       }
+
+       alts = &iface->altsetting[0];
+       altsd = get_iface_desc(alts);
+       if ((altsd->bInterfaceClass == USB_CLASS_AUDIO ||
+            altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC) &&
+           altsd->bInterfaceSubClass == USB_SUBCLASS_MIDISTREAMING) {
+               int err = snd_usbmidi_create(chip->card, iface,
+                                            &chip->midi_list, NULL);
+               if (err < 0) {
+                       snd_printk(KERN_ERR "%d:%u:%d: cannot create sequencer device\n",
+                                               dev->devnum, ctrlif, interface);
+                       return -EINVAL;
+               }
+               usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L);
+
+               return 0;
+       }
+
+       if ((altsd->bInterfaceClass != USB_CLASS_AUDIO &&
+            altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) ||
+           altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING) {
+               snd_printdd(KERN_ERR "%d:%u:%d: skipping non-supported interface %d\n",
+                                       dev->devnum, ctrlif, interface, altsd->bInterfaceClass);
+               /* skip non-supported classes */
+               return -EINVAL;
+       }
+
+       if (snd_usb_get_speed(dev) == USB_SPEED_LOW) {
+               snd_printk(KERN_ERR "low speed audio streaming not supported\n");
+               return -EINVAL;
+       }
+
+       if (! parse_audio_endpoints(chip, interface)) {
+               usb_set_interface(dev, interface, 0); /* reset the current interface */
+               usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 /*
  * parse audio control descriptor and create pcm/midi streams
  */
@@ -2856,67 +3138,81 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
 {
        struct usb_device *dev = chip->dev;
        struct usb_host_interface *host_iface;
-       struct usb_interface *iface;
-       unsigned char *p1;
-       int i, j;
+       struct usb_interface_descriptor *altsd;
+       void *control_header;
+       int i, protocol;
 
        /* find audiocontrol interface */
        host_iface = &usb_ifnum_to_if(dev, ctrlif)->altsetting[0];
-       if (!(p1 = snd_usb_find_csint_desc(host_iface->extra, host_iface->extralen, NULL, HEADER))) {
-               snd_printk(KERN_ERR "cannot find HEADER\n");
-               return -EINVAL;
-       }
-       if (! p1[7] || p1[0] < 8 + p1[7]) {
-               snd_printk(KERN_ERR "invalid HEADER\n");
+       control_header = snd_usb_find_csint_desc(host_iface->extra,
+                                                host_iface->extralen,
+                                                NULL, UAC_HEADER);
+       altsd = get_iface_desc(host_iface);
+       protocol = altsd->bInterfaceProtocol;
+
+       if (!control_header) {
+               snd_printk(KERN_ERR "cannot find UAC_HEADER\n");
                return -EINVAL;
        }
 
-       /*
-        * parse all USB audio streaming interfaces
-        */
-       for (i = 0; i < p1[7]; i++) {
-               struct usb_host_interface *alts;
-               struct usb_interface_descriptor *altsd;
-               j = p1[8 + i];
-               iface = usb_ifnum_to_if(dev, j);
-               if (!iface) {
-                       snd_printk(KERN_ERR "%d:%u:%d : does not exist\n",
-                                  dev->devnum, ctrlif, j);
-                       continue;
-               }
-               if (usb_interface_claimed(iface)) {
-                       snd_printdd(KERN_INFO "%d:%d:%d: skipping, already claimed\n", dev->devnum, ctrlif, j);
-                       continue;
+       switch (protocol) {
+       case UAC_VERSION_1: {
+               struct uac_ac_header_descriptor_v1 *h1 = control_header;
+
+               if (!h1->bInCollection) {
+                       snd_printk(KERN_INFO "skipping empty audio interface (v1)\n");
+                       return -EINVAL;
                }
-               alts = &iface->altsetting[0];
-               altsd = get_iface_desc(alts);
-               if ((altsd->bInterfaceClass == USB_CLASS_AUDIO ||
-                    altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC) &&
-                   altsd->bInterfaceSubClass == USB_SUBCLASS_MIDI_STREAMING) {
-                       int err = snd_usbmidi_create(chip->card, iface,
-                                                    &chip->midi_list, NULL);
-                       if (err < 0) {
-                               snd_printk(KERN_ERR "%d:%u:%d: cannot create sequencer device\n", dev->devnum, ctrlif, j);
-                               continue;
-                       }
-                       usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L);
-                       continue;
+
+               if (h1->bLength < sizeof(*h1) + h1->bInCollection) {
+                       snd_printk(KERN_ERR "invalid UAC_HEADER (v1)\n");
+                       return -EINVAL;
                }
-               if ((altsd->bInterfaceClass != USB_CLASS_AUDIO &&
-                    altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) ||
-                   altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIO_STREAMING) {
-                       snd_printdd(KERN_ERR "%d:%u:%d: skipping non-supported interface %d\n", dev->devnum, ctrlif, j, altsd->bInterfaceClass);
-                       /* skip non-supported classes */
-                       continue;
+
+               for (i = 0; i < h1->bInCollection; i++)
+                       snd_usb_create_stream(chip, ctrlif, h1->baInterfaceNr[i]);
+
+               break;
+       }
+
+       case UAC_VERSION_2: {
+               struct uac_clock_source_descriptor *cs;
+               struct usb_interface_assoc_descriptor *assoc =
+                       usb_ifnum_to_if(dev, ctrlif)->intf_assoc;
+
+               if (!assoc) {
+                       snd_printk(KERN_ERR "Audio class v2 interfaces need an interface association\n");
+                       return -EINVAL;
                }
-               if (snd_usb_get_speed(dev) == USB_SPEED_LOW) {
-                       snd_printk(KERN_ERR "low speed audio streaming not supported\n");
-                       continue;
+
+               /* FIXME: for now, we expect there is at least one clock source
+                * descriptor and we always take the first one.
+                * We should properly support devices with multiple clock sources,
+                * clock selectors and sample rate conversion units. */
+
+               cs = snd_usb_find_csint_desc(host_iface->extra, host_iface->extralen,
+                                               NULL, UAC_CLOCK_SOURCE);
+
+               if (!cs) {
+                       snd_printk(KERN_ERR "CLOCK_SOURCE descriptor not found\n");
+                       return -EINVAL;
                }
-               if (! parse_audio_endpoints(chip, j)) {
-                       usb_set_interface(dev, j, 0); /* reset the current interface */
-                       usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L);
+
+               chip->clock_id = cs->bClockID;
+
+               for (i = 0; i < assoc->bInterfaceCount; i++) {
+                       int intf = assoc->bFirstInterface + i;
+
+                       if (intf != ctrlif)
+                               snd_usb_create_stream(chip, ctrlif, intf);
                }
+
+               break;
+       }
+
+       default:
+               snd_printk(KERN_ERR "unknown protocol version 0x%02x\n", protocol);
+               return -EINVAL;
        }
 
        return 0;
@@ -3007,7 +3303,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
        static const struct audioformat ua_format = {
                .format = SNDRV_PCM_FORMAT_S24_3LE,
                .channels = 2,
-               .fmt_type = USB_FORMAT_TYPE_I,
+               .fmt_type = UAC_FORMAT_TYPE_I,
                .altsetting = 1,
                .altset_idx = 1,
                .rates = SNDRV_PCM_RATE_CONTINUOUS,
@@ -3099,7 +3395,7 @@ static int create_ua1000_quirk(struct snd_usb_audio *chip,
 {
        static const struct audioformat ua1000_format = {
                .format = SNDRV_PCM_FORMAT_S32_LE,
-               .fmt_type = USB_FORMAT_TYPE_I,
+               .fmt_type = UAC_FORMAT_TYPE_I,
                .altsetting = 1,
                .altset_idx = 1,
                .attributes = 0,
@@ -3142,59 +3438,6 @@ static int create_ua1000_quirk(struct snd_usb_audio *chip,
        return 0;
 }
 
-/*
- * Create a stream for an Edirol UA-101 interface.
- * Copy, paste and modify from Edirol UA-1000
- */
-static int create_ua101_quirk(struct snd_usb_audio *chip,
-                              struct usb_interface *iface,
-                              const struct snd_usb_audio_quirk *quirk)
-{
-       static const struct audioformat ua101_format = {
-               .format = SNDRV_PCM_FORMAT_S32_LE,
-               .fmt_type = USB_FORMAT_TYPE_I,
-               .altsetting = 1,
-               .altset_idx = 1,
-               .attributes = 0,
-               .rates = SNDRV_PCM_RATE_CONTINUOUS,
-       };
-       struct usb_host_interface *alts;
-       struct usb_interface_descriptor *altsd;
-       struct audioformat *fp;
-       int stream, err;
-
-       if (iface->num_altsetting != 2)
-               return -ENXIO;
-       alts = &iface->altsetting[1];
-       altsd = get_iface_desc(alts);
-       if (alts->extralen != 18 || alts->extra[1] != USB_DT_CS_INTERFACE ||
-           altsd->bNumEndpoints != 1)
-               return -ENXIO;
-
-       fp = kmemdup(&ua101_format, sizeof(*fp), GFP_KERNEL);
-       if (!fp)
-               return -ENOMEM;
-
-       fp->channels = alts->extra[11];
-       fp->iface = altsd->bInterfaceNumber;
-       fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
-       fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
-       fp->datainterval = parse_datainterval(chip, alts);
-       fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
-       fp->rate_max = fp->rate_min = combine_triple(&alts->extra[15]);
-
-       stream = (fp->endpoint & USB_DIR_IN)
-               ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
-       err = add_audio_endpoint(chip, stream, fp);
-       if (err < 0) {
-               kfree(fp);
-               return err;
-       }
-       /* FIXME: playback must be synchronized to capture */
-       usb_set_interface(chip->dev, fp->iface, 0);
-       return 0;
-}
-
 static int snd_usb_create_quirk(struct snd_usb_audio *chip,
                                struct usb_interface *iface,
                                const struct snd_usb_audio_quirk *quirk);
@@ -3232,6 +3475,18 @@ static int ignore_interface_quirk(struct snd_usb_audio *chip,
        return 0;
 }
 
+/*
+ * Allow alignment on audio sub-slot (channel samples) rather than
+ * on audio slots (audio frames)
+ */
+static int create_align_transfer_quirk(struct snd_usb_audio *chip,
+                                 struct usb_interface *iface,
+                                 const struct snd_usb_audio_quirk *quirk)
+{
+       chip->txfr_quirk = 1;
+       return 1;       /* Continue with creating streams and mixer */
+}
+
 
 /*
  * boot quirks
@@ -3326,6 +3581,32 @@ static int snd_usb_cm6206_boot_quirk(struct usb_device *dev)
        return err;
 }
 
+/*
+ * This call will put the synth in "USB send" mode, i.e it will send MIDI
+ * messages through USB (this is disabled at startup). The synth will
+ * acknowledge by sending a sysex on endpoint 0x85 and by displaying a USB
+ * sign on its LCD. Values here are chosen based on sniffing USB traffic
+ * under Windows.
+ */
+static int snd_usb_accessmusic_boot_quirk(struct usb_device *dev)
+{
+       int err, actual_length;
+
+       /* "midi send" enable */
+       static const u8 seq[] = { 0x4e, 0x73, 0x52, 0x01 };
+
+       void *buf = kmemdup(seq, ARRAY_SIZE(seq), GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+       err = usb_interrupt_msg(dev, usb_sndintpipe(dev, 0x05), buf,
+                       ARRAY_SIZE(seq), &actual_length, 1000);
+       kfree(buf);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
 /*
  * Setup quirks
  */
@@ -3406,8 +3687,8 @@ static int snd_usb_create_quirk(struct snd_usb_audio *chip,
                [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk,
                [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,
                [QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk,
-               [QUIRK_AUDIO_EDIROL_UA101] = create_ua101_quirk,
-               [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk
+               [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk,
+               [QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk
        };
 
        if (quirk->type < QUIRK_TYPE_COUNT) {
@@ -3596,7 +3877,6 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
        ifnum = get_iface_desc(alts)->bInterfaceNumber;
        id = USB_ID(le16_to_cpu(dev->descriptor.idVendor),
                    le16_to_cpu(dev->descriptor.idProduct));
-
        if (quirk && quirk->ifnum >= 0 && ifnum != quirk->ifnum)
                goto __err_val;
 
@@ -3624,6 +3904,12 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
                        goto __err_val;
        }
 
+       /* Access Music VirusTI Desktop */
+       if (id == USB_ID(0x133e, 0x0815)) {
+               if (snd_usb_accessmusic_boot_quirk(dev) < 0)
+                       goto __err_val;
+       }
+
        /*
         * found a config.  now register to ALSA
         */
@@ -3661,6 +3947,7 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
                }
        }
 
+       chip->txfr_quirk = 0;
        err = 1; /* continue */
        if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) {
                /* need some special handlings */
index 40ba8115fb8131fcf38c1ef07abeded673b747ab..6b016d4aac6b102b02103336b1a9b6cdb450368e 100644 (file)
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-
-/*
- */
-
-#define USB_SUBCLASS_AUDIO_CONTROL     0x01
-#define USB_SUBCLASS_AUDIO_STREAMING   0x02
-#define USB_SUBCLASS_MIDI_STREAMING    0x03
-#define USB_SUBCLASS_VENDOR_SPEC       0xff
-
-#define HEADER                         0x01
-#define INPUT_TERMINAL                 0x02
-#define OUTPUT_TERMINAL                        0x03
-#define MIXER_UNIT                     0x04
-#define SELECTOR_UNIT                  0x05
-#define FEATURE_UNIT                   0x06
-#define PROCESSING_UNIT                        0x07
-#define EXTENSION_UNIT                 0x08
-
-#define AS_GENERAL                     0x01
-#define FORMAT_TYPE                    0x02
-#define FORMAT_SPECIFIC                        0x03
-
-#define EP_GENERAL                     0x01
-
-#define MS_GENERAL                     0x01
-#define MIDI_IN_JACK                   0x02
-#define MIDI_OUT_JACK                  0x03
-
-/* endpoint attributes */
-#define EP_ATTR_MASK                   0x0c
-#define EP_ATTR_ASYNC                  0x04
-#define EP_ATTR_ADAPTIVE               0x08
-#define EP_ATTR_SYNC                   0x0c
-
-/* cs endpoint attributes */
-#define EP_CS_ATTR_SAMPLE_RATE         0x01
-#define EP_CS_ATTR_PITCH_CONTROL       0x02
-#define EP_CS_ATTR_FILL_MAX            0x80
-
-/* Audio Class specific Request Codes */
-
-#define SET_CUR    0x01
-#define GET_CUR    0x81
-#define SET_MIN    0x02
-#define GET_MIN    0x82
-#define SET_MAX    0x03
-#define GET_MAX    0x83
-#define SET_RES    0x04
-#define GET_RES    0x84
-#define SET_MEM    0x05
-#define GET_MEM    0x85
-#define GET_STAT   0xff
-
-/* Terminal Control Selectors */
-
-#define COPY_PROTECT_CONTROL       0x01
-
-/* Endpoint Control Selectors */
-
-#define SAMPLING_FREQ_CONTROL      0x01
-#define PITCH_CONTROL              0x02
-
-/* Format Types */
-#define USB_FORMAT_TYPE_I      0x01
-#define USB_FORMAT_TYPE_II     0x02
-#define USB_FORMAT_TYPE_III    0x03
-
-/* type I */
-#define USB_AUDIO_FORMAT_PCM   0x01
-#define USB_AUDIO_FORMAT_PCM8  0x02
-#define USB_AUDIO_FORMAT_IEEE_FLOAT    0x03
-#define USB_AUDIO_FORMAT_ALAW  0x04
-#define USB_AUDIO_FORMAT_MU_LAW        0x05
-
-/* type II */
-#define USB_AUDIO_FORMAT_MPEG  0x1001
-#define USB_AUDIO_FORMAT_AC3   0x1002
-
-/* type III */
-#define USB_AUDIO_FORMAT_IEC1937_AC3   0x2001
-#define USB_AUDIO_FORMAT_IEC1937_MPEG1_LAYER1  0x2002
-#define USB_AUDIO_FORMAT_IEC1937_MPEG2_NOEXT   0x2003
-#define USB_AUDIO_FORMAT_IEC1937_MPEG2_EXT     0x2004
-#define USB_AUDIO_FORMAT_IEC1937_MPEG2_LAYER1_LS       0x2005
-#define USB_AUDIO_FORMAT_IEC1937_MPEG2_LAYER23_LS      0x2006
-
-
 /* maximum number of endpoints per interface */
 #define MIDI_MAX_ENDPOINTS 2
 
@@ -125,9 +38,13 @@ struct snd_usb_audio {
        struct snd_card *card;
        u32 usb_id;
        int shutdown;
+       unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */
        int num_interfaces;
        int num_suspended_intf;
 
+       /* for audio class v2 */
+       int clock_id;
+
        struct list_head pcm_list;      /* list of pcm streams */
        int pcm_devs;
 
@@ -159,8 +76,8 @@ enum quirk_type {
        QUIRK_AUDIO_STANDARD_INTERFACE,
        QUIRK_AUDIO_FIXED_ENDPOINT,
        QUIRK_AUDIO_EDIROL_UA1000,
-       QUIRK_AUDIO_EDIROL_UA101,
        QUIRK_AUDIO_EDIROL_UAXX,
+       QUIRK_AUDIO_ALIGN_TRANSFER,
 
        QUIRK_TYPE_COUNT
 };
@@ -209,6 +126,16 @@ struct snd_usb_midi_endpoint_info {
 /*
  */
 
+/*E-mu USB samplerate control quirk*/
+enum {
+       EMU_QUIRK_SR_44100HZ = 0,
+       EMU_QUIRK_SR_48000HZ,
+       EMU_QUIRK_SR_88200HZ,
+       EMU_QUIRK_SR_96000HZ,
+       EMU_QUIRK_SR_176400HZ,
+       EMU_QUIRK_SR_192000HZ
+};
+
 #define combine_word(s)    ((*(s)) | ((unsigned int)(s)[1] << 8))
 #define combine_triple(s)  (combine_word(s) | ((unsigned int)(s)[2] << 16))
 #define combine_quad(s)    (combine_triple(s) | ((unsigned int)(s)[3] << 24))
@@ -234,6 +161,9 @@ void snd_usbmidi_input_stop(struct list_head* p);
 void snd_usbmidi_input_start(struct list_head* p);
 void snd_usbmidi_disconnect(struct list_head *p);
 
+void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
+                       unsigned char samplerate_id);
+
 /*
  * retrieve usb_interface descriptor from the host interface
  * (conditional for compatibility with the older API)
index 6e89b8368d9ae2bcb315dd74fb28026cec25af99..2c59afd99611b363651d77afe0e0f2ef26be0ebb 100644 (file)
@@ -46,6 +46,8 @@
 #include <linux/timer.h>
 #include <linux/usb.h>
 #include <linux/wait.h>
+#include <linux/usb/audio.h>
+
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/rawmidi.h>
@@ -1162,10 +1164,22 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi,
                pipe = usb_sndintpipe(umidi->dev, ep_info->out_ep);
        else
                pipe = usb_sndbulkpipe(umidi->dev, ep_info->out_ep);
-       if (umidi->usb_id == USB_ID(0x0a92, 0x1020)) /* ESI M4U */
-               ep->max_transfer = 4;
-       else
+       switch (umidi->usb_id) {
+       default:
                ep->max_transfer = usb_maxpacket(umidi->dev, pipe, 1);
+               break;
+               /*
+                * Various chips declare a packet size larger than 4 bytes, but
+                * do not actually work with larger packets:
+                */
+       case USB_ID(0x0a92, 0x1020): /* ESI M4U */
+       case USB_ID(0x1430, 0x474b): /* RedOctane GH MIDI INTERFACE */
+       case USB_ID(0x15ca, 0x0101): /* Textech USB Midi Cable */
+       case USB_ID(0x15ca, 0x1806): /* Textech USB Midi Cable */
+       case USB_ID(0x1a86, 0x752d): /* QinHeng CH345 "USB2.0-MIDI" */
+               ep->max_transfer = 4;
+               break;
+       }
        for (i = 0; i < OUTPUT_URBS; ++i) {
                buffer = usb_buffer_alloc(umidi->dev,
                                          ep->max_transfer, GFP_KERNEL,
@@ -1407,6 +1421,12 @@ static struct port_info {
        EXTERNAL_PORT(0x086a, 0x0001, 8, "%s Broadcast"),
        EXTERNAL_PORT(0x086a, 0x0002, 8, "%s Broadcast"),
        EXTERNAL_PORT(0x086a, 0x0003, 4, "%s Broadcast"),
+       /* Access Music Virus TI */
+       EXTERNAL_PORT(0x133e, 0x0815, 0, "%s MIDI"),
+       PORT_INFO(0x133e, 0x0815, 1, "%s Synth", 0,
+               SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
+               SNDRV_SEQ_PORT_TYPE_HARDWARE |
+               SNDRV_SEQ_PORT_TYPE_SYNTHESIZER),
 };
 
 static struct port_info *find_port_info(struct snd_usb_midi* umidi, int number)
@@ -1522,7 +1542,7 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi,
        if (hostif->extralen >= 7 &&
            ms_header->bLength >= 7 &&
            ms_header->bDescriptorType == USB_DT_CS_INTERFACE &&
-           ms_header->bDescriptorSubtype == HEADER)
+           ms_header->bDescriptorSubtype == UAC_HEADER)
                snd_printdd(KERN_INFO "MIDIStreaming version %02x.%02x\n",
                            ms_header->bcdMSC[1], ms_header->bcdMSC[0]);
        else
@@ -1538,7 +1558,7 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi,
                if (hostep->extralen < 4 ||
                    ms_ep->bLength < 4 ||
                    ms_ep->bDescriptorType != USB_DT_CS_ENDPOINT ||
-                   ms_ep->bDescriptorSubtype != MS_GENERAL)
+                   ms_ep->bDescriptorSubtype != UAC_MS_GENERAL)
                        continue;
                if (usb_endpoint_dir_out(ep)) {
                        if (endpoints[epidx].out_ep) {
@@ -1750,9 +1770,9 @@ static int snd_usbmidi_detect_yamaha(struct snd_usb_midi* umidi,
             cs_desc < hostif->extra + hostif->extralen && cs_desc[0] >= 2;
             cs_desc += cs_desc[0]) {
                if (cs_desc[1] == USB_DT_CS_INTERFACE) {
-                       if (cs_desc[2] == MIDI_IN_JACK)
+                       if (cs_desc[2] == UAC_MIDI_IN_JACK)
                                endpoint->in_cables = (endpoint->in_cables << 1) | 1;
-                       else if (cs_desc[2] == MIDI_OUT_JACK)
+                       else if (cs_desc[2] == UAC_MIDI_OUT_JACK)
                                endpoint->out_cables = (endpoint->out_cables << 1) | 1;
                }
        }
index c998220b99c62e30c4d32276478ed7e15c2ca7c5..8e8f871b74ca477dc26053b5b0dbf74136d3bdc0 100644 (file)
@@ -32,6 +32,8 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/usb.h>
+#include <linux/usb/audio.h>
+
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/hwdep.h>
@@ -69,13 +71,16 @@ static const struct rc_config {
        { USB_ID(0x041e, 0x3048), 2, 2, 6, 6,  2,  0x6e91 }, /* Toshiba SB0500 */
 };
 
+#define MAX_ID_ELEMS   256
+
 struct usb_mixer_interface {
        struct snd_usb_audio *chip;
        unsigned int ctrlif;
        struct list_head list;
        unsigned int ignore_ctl_error;
        struct urb *urb;
-       struct usb_mixer_elem_info **id_elems; /* array[256], indexed by unit id */
+       /* array[MAX_ID_ELEMS], indexed by unit id */
+       struct usb_mixer_elem_info **id_elems;
 
        /* Sound Blaster remote control stuff */
        const struct rc_config *rc_cfg;
@@ -105,7 +110,7 @@ struct mixer_build {
        struct usb_mixer_interface *mixer;
        unsigned char *buffer;
        unsigned int buflen;
-       DECLARE_BITMAP(unitbitmap, 256);
+       DECLARE_BITMAP(unitbitmap, MAX_ID_ELEMS);
        struct usb_audio_term oterm;
        const struct usbmix_name_map *map;
        const struct usbmix_selector_map *selector_map;
@@ -123,6 +128,7 @@ struct usb_mixer_elem_info {
        int channels;
        int val_type;
        int min, max, res;
+       int dBmin, dBmax;
        int cached;
        int cache_val[MAX_CHANNELS];
        u8 initialized;
@@ -186,6 +192,21 @@ enum {
        USB_PROC_DCR_RELEASE = 6,
 };
 
+/*E-mu 0202(0404) eXtension Unit(XU) control*/
+enum {
+       USB_XU_CLOCK_RATE               = 0xe301,
+       USB_XU_CLOCK_SOURCE             = 0xe302,
+       USB_XU_DIGITAL_IO_STATUS        = 0xe303,
+       USB_XU_DEVICE_OPTIONS           = 0xe304,
+       USB_XU_DIRECT_MONITORING        = 0xe305,
+       USB_XU_METERING                 = 0xe306
+};
+enum {
+       USB_XU_CLOCK_SOURCE_SELECTOR = 0x02,    /* clock source*/
+       USB_XU_CLOCK_RATE_SELECTOR = 0x03,      /* clock rate */
+       USB_XU_DIGITAL_FORMAT_SELECTOR = 0x01,  /* the spdif format */
+       USB_XU_SOFT_LIMIT_SELECTOR = 0x03       /* soft limiter */
+};
 
 /*
  * manual mapping of mixer names
@@ -194,42 +215,50 @@ enum {
  */
 #include "usbmixer_maps.c"
 
-/* get the mapped name if the unit matches */
-static int check_mapped_name(struct mixer_build *state, int unitid, int control, char *buf, int buflen)
+static const struct usbmix_name_map *
+find_map(struct mixer_build *state, int unitid, int control)
 {
-       const struct usbmix_name_map *p;
+       const struct usbmix_name_map *p = state->map;
 
-       if (! state->map)
-               return 0;
+       if (!p)
+               return NULL;
 
        for (p = state->map; p->id; p++) {
-               if (p->id == unitid && p->name &&
-                   (! control || ! p->control || control == p->control)) {
-                       buflen--;
-                       return strlcpy(buf, p->name, buflen);
-               }
+               if (p->id == unitid &&
+                   (!control || !p->control || control == p->control))
+                       return p;
        }
-       return 0;
+       return NULL;
 }
 
-/* check whether the control should be ignored */
-static int check_ignored_ctl(struct mixer_build *state, int unitid, int control)
+/* get the mapped name if the unit matches */
+static int
+check_mapped_name(const struct usbmix_name_map *p, char *buf, int buflen)
 {
-       const struct usbmix_name_map *p;
+       if (!p || !p->name)
+               return 0;
+
+       buflen--;
+       return strlcpy(buf, p->name, buflen);
+}
 
-       if (! state->map)
+/* check whether the control should be ignored */
+static inline int
+check_ignored_ctl(const struct usbmix_name_map *p)
+{
+       if (!p || p->name || p->dB)
                return 0;
-       for (p = state->map; p->id; p++) {
-               if (p->id == unitid && ! p->name &&
-                   (! control || ! p->control || control == p->control)) {
-                       /*
-                       printk(KERN_DEBUG "ignored control %d:%d\n",
-                              unitid, control);
-                       */
-                       return 1;
-               }
+       return 1;
+}
+
+/* dB mapping */
+static inline void check_mapped_dB(const struct usbmix_name_map *p,
+                                  struct usb_mixer_elem_info *cval)
+{
+       if (p && p->dB) {
+               cval->dBmin = p->dB->min;
+               cval->dBmax = p->dB->max;
        }
-       return 0;
 }
 
 /* get the mapped selector source name */
@@ -257,7 +286,7 @@ static void *find_audio_control_unit(struct mixer_build *state, unsigned char un
        p = NULL;
        while ((p = snd_usb_find_desc(state->buffer, state->buflen, p,
                                      USB_DT_CS_INTERFACE)) != NULL) {
-               if (p[0] >= 4 && p[2] >= INPUT_TERMINAL && p[2] <= EXTENSION_UNIT && p[3] == unit)
+               if (p[0] >= 4 && p[2] >= UAC_INPUT_TERMINAL && p[2] <= UAC_EXTENSION_UNIT_V1 && p[3] == unit)
                        return p;
        }
        return NULL;
@@ -378,14 +407,14 @@ static int get_ctl_value(struct usb_mixer_elem_info *cval, int request, int vali
 
 static int get_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int *value)
 {
-       return get_ctl_value(cval, GET_CUR, validx, value);
+       return get_ctl_value(cval, UAC_GET_CUR, validx, value);
 }
 
 /* channel = 0: master, 1 = first channel */
 static inline int get_cur_mix_raw(struct usb_mixer_elem_info *cval,
                                  int channel, int *value)
 {
-       return get_ctl_value(cval, GET_CUR, (cval->control << 8) | channel, value);
+       return get_ctl_value(cval, UAC_GET_CUR, (cval->control << 8) | channel, value);
 }
 
 static int get_cur_mix_value(struct usb_mixer_elem_info *cval,
@@ -439,14 +468,14 @@ static int set_ctl_value(struct usb_mixer_elem_info *cval, int request, int vali
 
 static int set_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int value)
 {
-       return set_ctl_value(cval, SET_CUR, validx, value);
+       return set_ctl_value(cval, UAC_SET_CUR, validx, value);
 }
 
 static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
                             int index, int value)
 {
        int err;
-       err = set_ctl_value(cval, SET_CUR, (cval->control << 8) | channel,
+       err = set_ctl_value(cval, UAC_SET_CUR, (cval->control << 8) | channel,
                            value);
        if (err < 0)
                return err;
@@ -466,20 +495,8 @@ static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
 
        if (size < sizeof(scale))
                return -ENOMEM;
-       /* USB descriptions contain the dB scale in 1/256 dB unit
-        * while ALSA TLV contains in 1/100 dB unit
-        */
-       scale[2] = (convert_signed_value(cval, cval->min) * 100) / 256;
-       scale[3] = (convert_signed_value(cval, cval->max) * 100) / 256;
-       if (scale[3] <= scale[2]) {
-               /* something is wrong; assume it's either from/to 0dB */
-               if (scale[2] < 0)
-                       scale[3] = 0;
-               else if (scale[2] > 0)
-                       scale[2] = 0;
-               else /* totally crap, return an error */
-                       return -EINVAL;
-       }
+       scale[2] = cval->dBmin;
+       scale[3] = cval->dBmax;
        if (copy_to_user(_tlv, scale, sizeof(scale)))
                return -EFAULT;
        return 0;
@@ -588,13 +605,13 @@ static int get_term_name(struct mixer_build *state, struct usb_audio_term *iterm
                if (term_only)
                        return 0;
                switch (iterm->type >> 16) {
-               case SELECTOR_UNIT:
+               case UAC_SELECTOR_UNIT:
                        strcpy(name, "Selector"); return 8;
-               case PROCESSING_UNIT:
+               case UAC_PROCESSING_UNIT_V1:
                        strcpy(name, "Process Unit"); return 12;
-               case EXTENSION_UNIT:
+               case UAC_EXTENSION_UNIT_V1:
                        strcpy(name, "Ext Unit"); return 8;
-               case MIXER_UNIT:
+               case UAC_MIXER_UNIT:
                        strcpy(name, "Mixer"); return 5;
                default:
                        return sprintf(name, "Unit %d", iterm->id);
@@ -633,22 +650,22 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_
        while ((p1 = find_audio_control_unit(state, id)) != NULL) {
                term->id = id;
                switch (p1[2]) {
-               case INPUT_TERMINAL:
+               case UAC_INPUT_TERMINAL:
                        term->type = combine_word(p1 + 4);
                        term->channels = p1[7];
                        term->chconfig = combine_word(p1 + 8);
                        term->name = p1[11];
                        return 0;
-               case FEATURE_UNIT:
+               case UAC_FEATURE_UNIT:
                        id = p1[4];
                        break; /* continue to parse */
-               case MIXER_UNIT:
+               case UAC_MIXER_UNIT:
                        term->type = p1[2] << 16; /* virtual type */
                        term->channels = p1[5 + p1[4]];
                        term->chconfig = combine_word(p1 + 6 + p1[4]);
                        term->name = p1[p1[0] - 1];
                        return 0;
-               case SELECTOR_UNIT:
+               case UAC_SELECTOR_UNIT:
                        /* call recursively to retrieve the channel info */
                        if (check_input_term(state, p1[5], term) < 0)
                                return -ENODEV;
@@ -656,8 +673,8 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_
                        term->id = id;
                        term->name = p1[9 + p1[0] - 1];
                        return 0;
-               case PROCESSING_UNIT:
-               case EXTENSION_UNIT:
+               case UAC_PROCESSING_UNIT_V1:
+               case UAC_EXTENSION_UNIT_V1:
                        if (p1[6] == 1) {
                                id = p1[7];
                                break; /* continue to parse */
@@ -720,6 +737,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
        cval->min = default_min;
        cval->max = cval->min + 1;
        cval->res = 1;
+       cval->dBmin = cval->dBmax = 0;
 
        if (cval->val_type == USB_MIXER_BOOLEAN ||
            cval->val_type == USB_MIXER_INV_BOOLEAN) {
@@ -734,23 +752,23 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
                                        break;
                                }
                }
-               if (get_ctl_value(cval, GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 ||
-                   get_ctl_value(cval, GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) {
+               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, cval->mixer->ctrlif, cval->control, cval->id);
                        return -EINVAL;
                }
-               if (get_ctl_value(cval, GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) {
+               if (get_ctl_value(cval, UAC_GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) {
                        cval->res = 1;
                } else {
                        int last_valid_res = cval->res;
 
                        while (cval->res > 1) {
-                               if (set_ctl_value(cval, SET_RES, (cval->control << 8) | minchn, cval->res / 2) < 0)
+                               if (set_ctl_value(cval, UAC_SET_RES, (cval->control << 8) | minchn, cval->res / 2) < 0)
                                        break;
                                cval->res /= 2;
                        }
-                       if (get_ctl_value(cval, GET_RES, (cval->control << 8) | minchn, &cval->res) < 0)
+                       if (get_ctl_value(cval, UAC_GET_RES, (cval->control << 8) | minchn, &cval->res) < 0)
                                cval->res = last_valid_res;
                }
                if (cval->res == 0)
@@ -787,6 +805,24 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
 
                cval->initialized = 1;
        }
+
+       /* USB descriptions contain the dB scale in 1/256 dB unit
+        * while ALSA TLV contains in 1/100 dB unit
+        */
+       cval->dBmin = (convert_signed_value(cval, cval->min) * 100) / 256;
+       cval->dBmax = (convert_signed_value(cval, cval->max) * 100) / 256;
+       if (cval->dBmin > cval->dBmax) {
+               /* something is wrong; assume it's either from/to 0dB */
+               if (cval->dBmin < 0)
+                       cval->dBmax = 0;
+               else if (cval->dBmin > 0)
+                       cval->dBmin = 0;
+               if (cval->dBmin > cval->dBmax) {
+                       /* totally crap, return an error */
+                       return -EINVAL;
+               }
+       }
+
        return 0;
 }
 
@@ -912,6 +948,7 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc,
        int nameid = desc[desc[0] - 1];
        struct snd_kcontrol *kctl;
        struct usb_mixer_elem_info *cval;
+       const struct usbmix_name_map *map;
 
        control++; /* change from zero-based to 1-based value */
 
@@ -920,7 +957,8 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc,
                return;
        }
 
-       if (check_ignored_ctl(state, unitid, control))
+       map = find_map(state, unitid, control);
+       if (check_ignored_ctl(map))
                return;
 
        cval = kzalloc(sizeof(*cval), GFP_KERNEL);
@@ -954,10 +992,11 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc,
        }
        kctl->private_free = usb_mixer_elem_free;
 
-       len = check_mapped_name(state, unitid, control, kctl->id.name, sizeof(kctl->id.name));
+       len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
        mapped_name = len != 0;
        if (! len && nameid)
-               len = snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name));
+               len = snd_usb_copy_string_desc(state, nameid,
+                               kctl->id.name, sizeof(kctl->id.name));
 
        switch (control) {
        case USB_FEATURE_MUTE:
@@ -995,6 +1034,7 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc,
                        kctl->vd[0].access |= 
                                SNDRV_CTL_ELEM_ACCESS_TLV_READ |
                                SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
+                       check_mapped_dB(map, cval);
                }
                break;
 
@@ -1048,29 +1088,30 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc,
  *
  * most of controlls are defined here.
  */
-static int parse_audio_feature_unit(struct mixer_build *state, int unitid, unsigned char *ftr)
+static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void *_ftr)
 {
        int channels, i, j;
        struct usb_audio_term iterm;
        unsigned int master_bits, first_ch_bits;
        int err, csize;
+       struct uac_feature_unit_descriptor *ftr = _ftr;
 
-       if (ftr[0] < 7 || ! (csize = ftr[5]) || ftr[0] < 7 + csize) {
-               snd_printk(KERN_ERR "usbaudio: unit %u: invalid FEATURE_UNIT descriptor\n", unitid);
+       if (ftr->bLength < 7 || ! (csize = ftr->bControlSize) || ftr->bLength < 7 + csize) {
+               snd_printk(KERN_ERR "usbaudio: unit %u: invalid UAC_FEATURE_UNIT descriptor\n", unitid);
                return -EINVAL;
        }
 
        /* parse the source unit */
-       if ((err = parse_audio_unit(state, ftr[4])) < 0)
+       if ((err = parse_audio_unit(state, ftr->bSourceID)) < 0)
                return err;
 
        /* determine the input source type and name */
-       if (check_input_term(state, ftr[4], &iterm) < 0)
+       if (check_input_term(state, ftr->bSourceID, &iterm) < 0)
                return -EINVAL;
 
-       channels = (ftr[0] - 7) / csize - 1;
+       channels = (ftr->bLength - 7) / csize - 1;
 
-       master_bits = snd_usb_combine_bytes(ftr + 6, csize);
+       master_bits = snd_usb_combine_bytes(ftr->controls, csize);
        /* master configuration quirks */
        switch (state->chip->usb_id) {
        case USB_ID(0x08bb, 0x2702):
@@ -1081,21 +1122,21 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, unsig
                break;
        }
        if (channels > 0)
-               first_ch_bits = snd_usb_combine_bytes(ftr + 6 + csize, csize);
+               first_ch_bits = snd_usb_combine_bytes(ftr->controls + csize, csize);
        else
                first_ch_bits = 0;
        /* check all control types */
        for (i = 0; i < 10; i++) {
                unsigned int ch_bits = 0;
                for (j = 0; j < channels; j++) {
-                       unsigned int mask = snd_usb_combine_bytes(ftr + 6 + csize * (j+1), csize);
+                       unsigned int mask = snd_usb_combine_bytes(ftr->controls + csize * (j+1), csize);
                        if (mask & (1 << i))
                                ch_bits |= (1 << j);
                }
                if (ch_bits & 1) /* the first channel must be set (for ease of programming) */
-                       build_feature_ctl(state, ftr, ch_bits, i, &iterm, unitid);
+                       build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid);
                if (master_bits & (1 << i))
-                       build_feature_ctl(state, ftr, 0, i, &iterm, unitid);
+                       build_feature_ctl(state, _ftr, 0, i, &iterm, unitid);
        }
 
        return 0;
@@ -1122,8 +1163,10 @@ static void build_mixer_unit_ctl(struct mixer_build *state, unsigned char *desc,
        unsigned int num_outs = desc[5 + input_pins];
        unsigned int i, len;
        struct snd_kcontrol *kctl;
+       const struct usbmix_name_map *map;
 
-       if (check_ignored_ctl(state, unitid, 0))
+       map = find_map(state, unitid, 0);
+       if (check_ignored_ctl(map))
                return;
 
        cval = kzalloc(sizeof(*cval), GFP_KERNEL);
@@ -1152,7 +1195,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state, unsigned char *desc,
        }
        kctl->private_free = usb_mixer_elem_free;
 
-       len = check_mapped_name(state, unitid, 0, kctl->id.name, sizeof(kctl->id.name));
+       len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
        if (! len)
                len = get_term_name(state, iterm, kctl->id.name, sizeof(kctl->id.name), 0);
        if (! len)
@@ -1330,7 +1373,32 @@ static struct procunit_info procunits[] = {
        { USB_PROC_DCR, "DCR", dcr_proc_info },
        { 0 },
 };
-
+/*
+ * predefined data for extension units
+ */
+static struct procunit_value_info clock_rate_xu_info[] = {
+       { USB_XU_CLOCK_RATE_SELECTOR, "Selector", USB_MIXER_U8, 0 },
+       { 0 }
+};
+static struct procunit_value_info clock_source_xu_info[] = {
+       { USB_XU_CLOCK_SOURCE_SELECTOR, "External", USB_MIXER_BOOLEAN },
+       { 0 }
+};
+static struct procunit_value_info spdif_format_xu_info[] = {
+       { USB_XU_DIGITAL_FORMAT_SELECTOR, "SPDIF/AC3", USB_MIXER_BOOLEAN },
+       { 0 }
+};
+static struct procunit_value_info soft_limit_xu_info[] = {
+       { USB_XU_SOFT_LIMIT_SELECTOR, " ", USB_MIXER_BOOLEAN },
+       { 0 }
+};
+static struct procunit_info extunits[] = {
+       { USB_XU_CLOCK_RATE, "Clock rate", clock_rate_xu_info },
+       { USB_XU_CLOCK_SOURCE, "DigitalIn CLK source", clock_source_xu_info },
+       { USB_XU_DIGITAL_IO_STATUS, "DigitalOut format:", spdif_format_xu_info },
+       { USB_XU_DEVICE_OPTIONS, "AnalogueIn Soft Limit", soft_limit_xu_info },
+       { 0 }
+};
 /*
  * build a processing/extension unit
  */
@@ -1342,6 +1410,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned
        int i, err, nameid, type, len;
        struct procunit_info *info;
        struct procunit_value_info *valinfo;
+       const struct usbmix_name_map *map;
        static struct procunit_value_info default_value_info[] = {
                { 0x01, "Switch", USB_MIXER_BOOLEAN },
                { 0 }
@@ -1371,7 +1440,8 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned
                /* FIXME: bitmap might be longer than 8bit */
                if (! (dsc[12 + num_ins] & (1 << (valinfo->control - 1))))
                        continue;
-               if (check_ignored_ctl(state, unitid, valinfo->control))
+               map = find_map(state, unitid, valinfo->control);
+               if (check_ignored_ctl(map))
                        continue;
                cval = kzalloc(sizeof(*cval), GFP_KERNEL);
                if (! cval) {
@@ -1391,8 +1461,18 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned
                        cval->max = dsc[15];
                        cval->res = 1;
                        cval->initialized = 1;
-               } else
-                       get_min_max(cval, valinfo->min_value);
+               } else {
+                       if (type == USB_XU_CLOCK_RATE) {
+                               /* E-Mu USB 0404/0202/TrackerPre
+                                * samplerate control quirk
+                                */
+                               cval->min = 0;
+                               cval->max = 5;
+                               cval->res = 1;
+                               cval->initialized = 1;
+                       } else
+                               get_min_max(cval, valinfo->min_value);
+               }
 
                kctl = snd_ctl_new1(&mixer_procunit_ctl, cval);
                if (! kctl) {
@@ -1402,8 +1482,9 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned
                }
                kctl->private_free = usb_mixer_elem_free;
 
-               if (check_mapped_name(state, unitid, cval->control, kctl->id.name, sizeof(kctl->id.name)))
-                       ;
+               if (check_mapped_name(map, kctl->id.name,
+                                               sizeof(kctl->id.name)))
+                       /* nothing */ ;
                else if (info->name)
                        strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name));
                else {
@@ -1433,7 +1514,7 @@ static int parse_audio_processing_unit(struct mixer_build *state, int unitid, un
 
 static int parse_audio_extension_unit(struct mixer_build *state, int unitid, unsigned char *desc)
 {
-       return build_audio_procunit(state, unitid, desc, NULL, "Extension Unit");
+       return build_audio_procunit(state, unitid, desc, extunits, "Extension Unit");
 }
 
 
@@ -1542,6 +1623,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi
        int err;
        struct usb_mixer_elem_info *cval;
        struct snd_kcontrol *kctl;
+       const struct usbmix_name_map *map;
        char **namelist;
 
        if (! num_ins || desc[0] < 5 + num_ins) {
@@ -1557,7 +1639,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi
        if (num_ins == 1) /* only one ? nonsense! */
                return 0;
 
-       if (check_ignored_ctl(state, unitid, 0))
+       map = find_map(state, unitid, 0);
+       if (check_ignored_ctl(map))
                return 0;
 
        cval = kzalloc(sizeof(*cval), GFP_KERNEL);
@@ -1612,7 +1695,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi
        kctl->private_free = usb_mixer_selector_elem_free;
 
        nameid = desc[desc[0] - 1];
-       len = check_mapped_name(state, unitid, 0, kctl->id.name, sizeof(kctl->id.name));
+       len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
        if (len)
                ;
        else if (nameid)
@@ -1656,17 +1739,17 @@ static int parse_audio_unit(struct mixer_build *state, int unitid)
        }
 
        switch (p1[2]) {
-       case INPUT_TERMINAL:
+       case UAC_INPUT_TERMINAL:
                return 0; /* NOP */
-       case MIXER_UNIT:
+       case UAC_MIXER_UNIT:
                return parse_audio_mixer_unit(state, unitid, p1);
-       case SELECTOR_UNIT:
+       case UAC_SELECTOR_UNIT:
                return parse_audio_selector_unit(state, unitid, p1);
-       case FEATURE_UNIT:
+       case UAC_FEATURE_UNIT:
                return parse_audio_feature_unit(state, unitid, p1);
-       case PROCESSING_UNIT:
+       case UAC_PROCESSING_UNIT_V1:
                return parse_audio_processing_unit(state, unitid, p1);
-       case EXTENSION_UNIT:
+       case UAC_EXTENSION_UNIT_V1:
                return parse_audio_extension_unit(state, unitid, p1);
        default:
                snd_printk(KERN_ERR "usbaudio: unit %u: unexpected type 0x%02x\n", unitid, p1[2]);
@@ -1696,11 +1779,11 @@ static int snd_usb_mixer_dev_free(struct snd_device *device)
 /*
  * create mixer controls
  *
- * walk through all OUTPUT_TERMINAL descriptors to search for mixers
+ * walk through all UAC_OUTPUT_TERMINAL descriptors to search for mixers
  */
 static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
 {
-       unsigned char *desc;
+       struct uac_output_terminal_descriptor_v1 *desc;
        struct mixer_build state;
        int err;
        const struct usbmix_ctl_map *map;
@@ -1724,14 +1807,14 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
        }
 
        desc = NULL;
-       while ((desc = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, desc, OUTPUT_TERMINAL)) != NULL) {
-               if (desc[0] < 9)
+       while ((desc = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, desc, UAC_OUTPUT_TERMINAL)) != NULL) {
+               if (desc->bLength < 9)
                        continue; /* invalid descriptor? */
-               set_bit(desc[3], state.unitbitmap);  /* mark terminal ID as visited */
-               state.oterm.id = desc[3];
-               state.oterm.type = combine_word(&desc[4]);
-               state.oterm.name = desc[8];
-               err = parse_audio_unit(&state, desc[7]);
+               set_bit(desc->bTerminalID, state.unitbitmap);  /* mark terminal ID as visited */
+               state.oterm.id = desc->bTerminalID;
+               state.oterm.type = le16_to_cpu(desc->wTerminalType);
+               state.oterm.name = desc->iTerminal;
+               err = parse_audio_unit(&state, desc->bSourceID);
                if (err < 0)
                        return err;
        }
@@ -1748,6 +1831,46 @@ static void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer,
                               info->elem_id);
 }
 
+static void snd_usb_mixer_dump_cval(struct snd_info_buffer *buffer,
+                                   int unitid,
+                                   struct usb_mixer_elem_info *cval)
+{
+       static char *val_types[] = {"BOOLEAN", "INV_BOOLEAN",
+                                   "S8", "U8", "S16", "U16"};
+       snd_iprintf(buffer, "  Unit: %i\n", unitid);
+       if (cval->elem_id)
+               snd_iprintf(buffer, "    Control: name=\"%s\", index=%i\n",
+                               cval->elem_id->name, cval->elem_id->index);
+       snd_iprintf(buffer, "    Info: id=%i, control=%i, cmask=0x%x, "
+                           "channels=%i, type=\"%s\"\n", cval->id,
+                           cval->control, cval->cmask, cval->channels,
+                           val_types[cval->val_type]);
+       snd_iprintf(buffer, "    Volume: min=%i, max=%i, dBmin=%i, dBmax=%i\n",
+                           cval->min, cval->max, cval->dBmin, cval->dBmax);
+}
+
+static void snd_usb_mixer_proc_read(struct snd_info_entry *entry,
+                                   struct snd_info_buffer *buffer)
+{
+       struct snd_usb_audio *chip = entry->private_data;
+       struct usb_mixer_interface *mixer;
+       struct usb_mixer_elem_info *cval;
+       int unitid;
+
+       list_for_each_entry(mixer, &chip->mixer_list, list) {
+               snd_iprintf(buffer,
+                       "USB Mixer: usb_id=0x%08x, ctrlif=%i, ctlerr=%i\n",
+                               chip->usb_id, mixer->ctrlif,
+                               mixer->ignore_ctl_error);
+               snd_iprintf(buffer, "Card: %s\n", chip->card->longname);
+               for (unitid = 0; unitid < MAX_ID_ELEMS; unitid++) {
+                       for (cval = mixer->id_elems[unitid]; cval;
+                                               cval = cval->next_id_elem)
+                               snd_usb_mixer_dump_cval(buffer, unitid, cval);
+               }
+       }
+}
+
 static void snd_usb_mixer_memory_change(struct usb_mixer_interface *mixer,
                                        int unitid)
 {
@@ -1924,7 +2047,7 @@ static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer)
        }
        mixer->rc_setup_packet->bRequestType =
                USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
-       mixer->rc_setup_packet->bRequest = GET_MEM;
+       mixer->rc_setup_packet->bRequest = UAC_GET_MEM;
        mixer->rc_setup_packet->wValue = cpu_to_le16(0);
        mixer->rc_setup_packet->wIndex = cpu_to_le16(0);
        mixer->rc_setup_packet->wLength = cpu_to_le16(len);
@@ -2047,7 +2170,7 @@ static void snd_audigy2nx_proc_read(struct snd_info_entry *entry,
                snd_iprintf(buffer, "%s: ", jacks[i].name);
                err = snd_usb_ctl_msg(mixer->chip->dev,
                                      usb_rcvctrlpipe(mixer->chip->dev, 0),
-                                     GET_MEM, USB_DIR_IN | USB_TYPE_CLASS |
+                                     UAC_GET_MEM, USB_DIR_IN | USB_TYPE_CLASS |
                                      USB_RECIP_INTERFACE, 0,
                                      jacks[i].unitid << 8, buf, 3, 100);
                if (err == 3 && (buf[0] == 3 || buf[0] == 6))
@@ -2109,6 +2232,24 @@ static int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer)
        return 0;
 }
 
+void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
+                              unsigned char samplerate_id)
+{
+       struct usb_mixer_interface *mixer;
+       struct usb_mixer_elem_info *cval;
+       int unitid = 12; /* SamleRate ExtensionUnit ID */
+
+       list_for_each_entry(mixer, &chip->mixer_list, list) {
+               cval = mixer->id_elems[unitid];
+               if (cval) {
+                       set_cur_ctl_value(cval, cval->control << 8,
+                                         samplerate_id);
+                       snd_usb_mixer_notify_id(mixer, unitid);
+               }
+               break;
+       }
+}
+
 int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
                         int ignore_error)
 {
@@ -2116,7 +2257,9 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
                .dev_free = snd_usb_mixer_dev_free
        };
        struct usb_mixer_interface *mixer;
-       int err;
+       struct snd_info_entry *entry;
+       struct usb_host_interface *host_iface;
+       int err, protocol;
 
        strcpy(chip->card->mixername, "USB Mixer");
 
@@ -2126,12 +2269,23 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
        mixer->chip = chip;
        mixer->ctrlif = ctrlif;
        mixer->ignore_ctl_error = ignore_error;
-       mixer->id_elems = kcalloc(256, sizeof(*mixer->id_elems), GFP_KERNEL);
+       mixer->id_elems = kcalloc(MAX_ID_ELEMS, sizeof(*mixer->id_elems),
+                                 GFP_KERNEL);
        if (!mixer->id_elems) {
                kfree(mixer);
                return -ENOMEM;
        }
 
+       host_iface = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0];
+       protocol = host_iface->desc.bInterfaceProtocol;
+
+       /* FIXME! */
+       if (protocol != UAC_VERSION_1) {
+               snd_printk(KERN_WARNING "mixer interface protocol 0x%02x not yet supported\n",
+                                       protocol);
+               return 0;
+       }
+
        if ((err = snd_usb_mixer_controls(mixer)) < 0 ||
            (err = snd_usb_mixer_status_create(mixer)) < 0)
                goto _error;
@@ -2142,8 +2296,6 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
        if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020) ||
            mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||
            mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) {
-               struct snd_info_entry *entry;
-
                if ((err = snd_audigy2nx_controls_create(mixer)) < 0)
                        goto _error;
                if (!snd_card_proc_new(chip->card, "audigy2nx", &entry))
@@ -2161,6 +2313,11 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
        err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops);
        if (err < 0)
                goto _error;
+
+       if (list_empty(&chip->mixer_list) &&
+           !snd_card_proc_new(chip->card, "usbmixer", &entry))
+               snd_info_set_text_ops(entry, chip, snd_usb_mixer_proc_read);
+
        list_add(&mixer->list, &chip->mixer_list);
        return 0;
 
index 77c35885e21cf40653076729f8b1d327b28af52a..79e903a6086207f24f60b3d8233f75187072b2ad 100644 (file)
  *
  */
 
+struct usbmix_dB_map {
+       u32 min;
+       u32 max;
+};
 
 struct usbmix_name_map {
        int id;
        const char *name;
        int control;
+       struct usbmix_dB_map *dB;
 };
 
 struct usbmix_selector_map {
@@ -72,7 +77,7 @@ static struct usbmix_name_map extigy_map[] = {
        { 8, "Line Playback" }, /* FU */
        /* 9: IT mic */
        { 10, "Mic Playback" }, /* FU */
-       { 11, "Capture Input Source" }, /* SU */
+       { 11, "Capture Source" }, /* SU */
        { 12, "Capture" }, /* FU */
        /* 13: OT pcm capture */
        /* 14: MU (w/o controls) */
@@ -102,6 +107,9 @@ static struct usbmix_name_map extigy_map[] = {
  * e.g. no Master and fake PCM volume
  *                     Pavel Mihaylov <bin@bash.info>
  */
+static struct usbmix_dB_map mp3plus_dB_1 = {-4781, 0}; /* just guess */
+static struct usbmix_dB_map mp3plus_dB_2 = {-1781, 618}; /* just guess */
+
 static struct usbmix_name_map mp3plus_map[] = {
        /* 1: IT pcm */
        /* 2: IT mic */
@@ -110,16 +118,19 @@ static struct usbmix_name_map mp3plus_map[] = {
        /* 5: OT digital out */
        /* 6: OT speaker */
        /* 7: OT pcm capture */
-       { 8, "Capture Input Source" }, /* FU, default PCM Capture Source */
+       { 8, "Capture Source" }, /* FU, default PCM Capture Source */
                /* (Mic, Input 1 = Line input, Input 2 = Optical input) */
        { 9, "Master Playback" }, /* FU, default Speaker 1 */
        /* { 10, "Mic Capture", 1 }, */ /* FU, Mic Capture */
-       /* { 10, "Mic Capture", 2 }, */ /* FU, Mic Capture */
+       { 10, /* "Mic Capture", */ NULL, 2, .dB = &mp3plus_dB_2 },
+               /* FU, Mic Capture */
        { 10, "Mic Boost", 7 }, /* FU, default Auto Gain Input */
-       { 11, "Line Capture" }, /* FU, default PCM Capture */
+       { 11, "Line Capture", .dB = &mp3plus_dB_2 },
+               /* FU, default PCM Capture */
        { 12, "Digital In Playback" }, /* FU, default PCM 1 */
-       /* { 13, "Mic Playback" }, */ /* FU, default Mic Playback */
-       { 14, "Line Playback" }, /* FU, default Speaker */
+       { 13, /* "Mic Playback", */ .dB = &mp3plus_dB_1 },
+               /* FU, default Mic Playback */
+       { 14, "Line Playback", .dB = &mp3plus_dB_1 }, /* FU, default Speaker */
        /* 15: MU */
        { 0 } /* terminator */
 };
index a892bda03df9d12f83006851fe5d82be7bc82347..f06faf7917b968b120a705e82b7f29dadf6e736a 100644 (file)
@@ -91,7 +91,7 @@
        .idVendor = 0x046d,
        .idProduct = 0x0850,
        .bInterfaceClass = USB_CLASS_AUDIO,
-       .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL
+       .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL
 },
 {
        .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
        .idVendor = 0x046d,
        .idProduct = 0x08ae,
        .bInterfaceClass = USB_CLASS_AUDIO,
-       .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL
+       .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL
 },
 {
        .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
        .idVendor = 0x046d,
        .idProduct = 0x08c6,
        .bInterfaceClass = USB_CLASS_AUDIO,
-       .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL
+       .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL
 },
 {
        .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
        .idVendor = 0x046d,
        .idProduct = 0x08f0,
        .bInterfaceClass = USB_CLASS_AUDIO,
-       .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL
+       .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL
 },
 {
        .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
        .idVendor = 0x046d,
        .idProduct = 0x08f5,
        .bInterfaceClass = USB_CLASS_AUDIO,
-       .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL
+       .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL
 },
 {
        .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
        .idVendor = 0x046d,
        .idProduct = 0x08f6,
        .bInterfaceClass = USB_CLASS_AUDIO,
-       .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL
+       .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL
 },
 {
        USB_DEVICE(0x046d, 0x0990),
@@ -301,7 +301,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                                        .iface = 1,
                                        .altsetting = 1,
                                        .altset_idx = 1,
-                                       .attributes = EP_CS_ATTR_FILL_MAX,
+                                       .attributes = UAC_EP_CS_ATTR_FILL_MAX,
                                        .endpoint = 0x81,
                                        .ep_attr = 0x05,
                                        .rates = SNDRV_PCM_RATE_CONTINUOUS,
@@ -1266,37 +1266,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
-/* Roland UA-101 in High-Speed Mode only */
-{
-       USB_DEVICE(0x0582, 0x007d),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               .vendor_name = "Roland",
-               .product_name = "UA-101",
-               .ifnum = QUIRK_ANY_INTERFACE,
-               .type = QUIRK_COMPOSITE,
-               .data = (const struct snd_usb_audio_quirk[]) {
-                       {
-                               .ifnum = 0,
-                               .type = QUIRK_AUDIO_EDIROL_UA101
-                       },
-                       {
-                               .ifnum = 1,
-                               .type = QUIRK_AUDIO_EDIROL_UA101
-                       },
-                       {
-                               .ifnum = 2,
-                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
-                               .data = & (const struct snd_usb_midi_endpoint_info) {
-                                       .out_cables = 0x0001,
-                                       .in_cables  = 0x0001
-                               }
-                       },
-                       {
-                               .ifnum = -1
-                       }
-               }
-       }
-},
 {
        /* has ID 0x0081 when not in "Advanced Driver" mode */
        USB_DEVICE(0x0582, 0x0080),
@@ -2073,6 +2042,33 @@ YAMAHA_DEVICE(0x7010, "UB99"),
        }
 },
 
+/* Access Music devices */
+{
+       /* VirusTI Desktop */
+       USB_DEVICE_VENDOR_SPEC(0x133e, 0x0815),
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = &(const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 3,
+                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
+                               .data = &(const struct snd_usb_midi_endpoint_info) {
+                                       .out_cables = 0x0003,
+                                       .in_cables  = 0x0003
+                               }
+                       },
+                       {
+                               .ifnum = 4,
+                               .type = QUIRK_IGNORE_INTERFACE
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
+
 /* */
 {
        /* aka. Serato Scratch Live DJ Box */
@@ -2105,6 +2101,165 @@ YAMAHA_DEVICE(0x7010, "UB99"),
        }
 },
 
+/* Hauppauge HVR-950Q and HVR-850 */
+{
+       USB_DEVICE_VENDOR_SPEC(0x2040, 0x7200),
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
+                      USB_DEVICE_ID_MATCH_INT_CLASS |
+                      USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+       .bInterfaceClass = USB_CLASS_AUDIO,
+       .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .vendor_name = "Hauppauge",
+               .product_name = "HVR-950Q",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_AUDIO_ALIGN_TRANSFER,
+       }
+},
+{
+       USB_DEVICE_VENDOR_SPEC(0x2040, 0x7201),
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
+                      USB_DEVICE_ID_MATCH_INT_CLASS |
+                      USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+       .bInterfaceClass = USB_CLASS_AUDIO,
+       .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .vendor_name = "Hauppauge",
+               .product_name = "HVR-950Q",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_AUDIO_ALIGN_TRANSFER,
+       }
+},
+{
+       USB_DEVICE_VENDOR_SPEC(0x2040, 0x7202),
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
+                      USB_DEVICE_ID_MATCH_INT_CLASS |
+                      USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+       .bInterfaceClass = USB_CLASS_AUDIO,
+       .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .vendor_name = "Hauppauge",
+               .product_name = "HVR-950Q",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_AUDIO_ALIGN_TRANSFER,
+       }
+},
+{
+       USB_DEVICE_VENDOR_SPEC(0x2040, 0x7203),
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
+                      USB_DEVICE_ID_MATCH_INT_CLASS |
+                      USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+       .bInterfaceClass = USB_CLASS_AUDIO,
+       .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .vendor_name = "Hauppauge",
+               .product_name = "HVR-950Q",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_AUDIO_ALIGN_TRANSFER,
+       }
+},
+{
+       USB_DEVICE_VENDOR_SPEC(0x2040, 0x7204),
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
+                      USB_DEVICE_ID_MATCH_INT_CLASS |
+                      USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+       .bInterfaceClass = USB_CLASS_AUDIO,
+       .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .vendor_name = "Hauppauge",
+               .product_name = "HVR-950Q",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_AUDIO_ALIGN_TRANSFER,
+       }
+},
+{
+       USB_DEVICE_VENDOR_SPEC(0x2040, 0x7205),
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
+                      USB_DEVICE_ID_MATCH_INT_CLASS |
+                      USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+       .bInterfaceClass = USB_CLASS_AUDIO,
+       .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .vendor_name = "Hauppauge",
+               .product_name = "HVR-950Q",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_AUDIO_ALIGN_TRANSFER,
+       }
+},
+{
+       USB_DEVICE_VENDOR_SPEC(0x2040, 0x7250),
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
+                      USB_DEVICE_ID_MATCH_INT_CLASS |
+                      USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+       .bInterfaceClass = USB_CLASS_AUDIO,
+       .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .vendor_name = "Hauppauge",
+               .product_name = "HVR-950Q",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_AUDIO_ALIGN_TRANSFER,
+       }
+},
+{
+       USB_DEVICE_VENDOR_SPEC(0x2040, 0x7230),
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
+                      USB_DEVICE_ID_MATCH_INT_CLASS |
+                      USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+       .bInterfaceClass = USB_CLASS_AUDIO,
+       .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .vendor_name = "Hauppauge",
+               .product_name = "HVR-850",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_AUDIO_ALIGN_TRANSFER,
+       }
+},
+
+/* Digidesign Mbox */
+{
+       /* Thanks to Clemens Ladisch <clemens@ladisch.de> */
+       USB_DEVICE(0x0dba, 0x1000),
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .vendor_name = "Digidesign",
+               .product_name = "MBox",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = (const struct snd_usb_audio_quirk[]){
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_IGNORE_INTERFACE,
+                       },
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .format = SNDRV_PCM_FORMAT_S24_3BE,
+                                       .channels = 2,
+                                       .iface = 1,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
+                                       .endpoint = 0x02,
+                                       .ep_attr = 0x01,
+                                       .maxpacksize = 0x130,
+                                       .rates = SNDRV_PCM_RATE_44100 |
+                                                SNDRV_PCM_RATE_48000,
+                                       .rate_min = 44100,
+                                       .rate_max = 48000,
+                                       .nr_rates = 2,
+                                       .rate_table = (unsigned int[]) {
+                                               44100, 48000
+                                       }
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+
+       }
+},
+
 {
        /*
         * Some USB MIDI devices don't have an audio control interface,
@@ -2113,7 +2268,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
        .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS |
                       USB_DEVICE_ID_MATCH_INT_SUBCLASS,
        .bInterfaceClass = USB_CLASS_AUDIO,
-       .bInterfaceSubClass = USB_SUBCLASS_MIDI_STREAMING,
+       .bInterfaceSubClass = USB_SUBCLASS_MIDISTREAMING,
        .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
                .ifnum = QUIRK_ANY_INTERFACE,
                .type = QUIRK_MIDI_STANDARD_INTERFACE
index 91bb29666d260813d758f8082fb02ccb59fe4eac..44deb21b17770b8d063793c979fdab72a5b0ecd1 100644 (file)
@@ -16,6 +16,8 @@
  * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include <linux/usb.h>
+#include <linux/usb/audio.h>
 #include <sound/core.h>
 #include <sound/hwdep.h>
 #include <sound/pcm.h>
@@ -315,9 +317,9 @@ static int us122l_set_sample_rate(struct usb_device *dev, int rate)
        data[0] = rate;
        data[1] = rate >> 8;
        data[2] = rate >> 16;
-       err = us122l_ctl_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR,
+       err = us122l_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR,
                             USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
-                            SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000);
+                            UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, data, 3, 1000);
        if (err < 0)
                snd_printk(KERN_ERR "%d: cannot set freq %d to ep 0x%x\n",
                           dev->devnum, rate, ep);